Есть ли способ добавить шаблоны, тип подписи к функции в GHCi?

^-- Нет, не совсем так. Мой вопрос касается ДОБАВЛЕНИЯ шаблонов и подписей типов в интерактивном режиме... что, по-видимому, невозможно.

Самые базовые вещи, которые вы могли попробовать сделать из ранних руководств, не будут работать в GHCi:

foo [] = []
foo (x:xs) = x : foo xs

Это работает, если вы поместите его в foo.hs и в приглашении GHCi наберете :load foo.hs. Затем вы можете вызвать foo для списка и вернуть список.

Ранние поиски в Google говорят вам, что в GHCi вам нужен оператор let. Но в этом случае (функция определена с несколькими шаблонами) это не сработает:

Prelude> let foo [] = []
Prelude> let foo (x:xs) = x : foo xs
Prelude> foo [1, 2, 3]
[1,2,3*** Exception: <interactive>:3:5-27: Non-exhaustive patterns 
    in function foo

Второе «let» перезаписало первое «let». Отказаться от let — не вариант. И ему не нравится, если вы вводите такие выражения, как foo :: [a] -> [a].

Учебники, кажется, обходят это и отправляют вас быстро помещать код в файлы. Что делать, если вы не хотите создавать файл и хотите работать в интерактивном режиме? Какие есть варианты?


person HostileFork says dont trust SE    schedule 27.07.2014    source источник
comment
возможный дубликат Как определить функцию в ghci для нескольких линии?   -  person Ionuț G. Stan    schedule 27.07.2014
comment
возможный дубликат многострочных команд в GHCi   -  person Sibi    schedule 27.07.2014
comment
@IonuțG.Stan Я читал это. Это не тот же вопрос. И знание того, что оператор let будет группироваться со всем после него, является очень специфической странностью. Таким образом, если у меня есть файл, полный определений из учебника, я говорю «пусть один раз», и не имеет значения, какое последующее содержимое?   -  person HostileFork says dont trust SE    schedule 27.07.2014


Ответы (2)


Нет. Вы не можете добавить новые шаблоны или сигнатуру типа к функции в GHCi после того, как вы запустили оператор, определяющий ее в оценщике.

В этом отношении вы также не должны рассматривать это как «добавление» построчно в исходном коде. Это просто удобство записи. Итак, когда вы смотрите на «многострочное» определение, например:

foo :: [a] -> [a]
foo [] = []
foo (x:xs) = x : foo xs

Все эти определения foo должны быть связаны вместе как группа. Вы не можете разделить их... например, это вызовет ошибку:

foo :: [a] -> [a]
foo [] = []

bar = 3

foo (x:xs) = x : foo xs

(Примечание. Однако сигнатура типа может быть разделена. Подробную информацию о том, насколько далеко она может быть разделена, см. в разделе Как определяется гранулярность блоков в Haskell? )

Чтобы собрать вещи в группу, вы можете использовать многострочный ввод в GHCi. Или вы можете сделать все это в одной строке с точкой с запятой:

let foo :: [a] -> [a] ; foo [] = [] ; foo (x:xs) = x : xs

Но вы не можете ввести входные данные, протестировать их, затем вставить и удалить отдельные шаблоны и снова протестировать их. Вся функция переопределяется с каждым let.

person HostileFork says dont trust SE    schedule 27.07.2014

Использовать многострочный ввод:

Prelude> :set +m
Prelude> let
Prelude| foo [] = []
Prelude| foo (x:xs) = x : foo xs
Prelude| 
Prelude> foo [1,2,3]
[1,2,3]
person vivian    schedule 27.07.2014
comment
Нет ли способа указать N шаблонов, попробовать, получить проблему и настроить ее без многострочного ввода, снова определяющего все шаблоны? - person HostileFork says dont trust SE; 27.07.2014
comment
@HostileFork, сейчас нет. Есть предположение, что из истории ввода можно восстановить весь многострочный ввод, но пока это не реализовано. - person vivian; 27.07.2014
comment
Хм. Кажется, нельзя разделить шаблоны для foo с вкраплениями другого определения (например, foo [] = [], за которым следует bar = 3, а затем foo (x:xs) = x : foo xs). Поэтому, даже если вы вводите их в исходный код, они фактически определены все в мгновенный... так что построчного и там нет. Верный? - person HostileFork says dont trust SE; 27.07.2014
comment
@HostileFork Все уравнения для одной функции/переменной должны быть последовательными, как в файле. И все от let до пустой строки анализируется за один раз, как блок let. (GHCi проявляет снисходительность, не требуя в этом случае дополнительного отступа для элементов блока.) - person Ørjan Johansen; 27.07.2014
comment
@HostileFork Кстати, в GHCi (и лямбдаботе) я склонен использовать явные ; и очень случайные {} фигурные скобки (не так часто, как вы думаете) вместо многострочных. В основном старая привычка, но у этого есть то преимущество, что я могу обычно повторно редактировать всю строку за один раз. - person Ørjan Johansen; 27.07.2014
comment
@ØrjanJohansen Спасибо... см. мою попытку ответить на мой собственный вопрос. Хотите добавить какой-нибудь нюанс? Кажется, сигнатура типа может быть отделена от определений функций, но вы не можете самостоятельно сделать сигнатуру типа, что я могу сказать... - person HostileFork says dont trust SE; 27.07.2014
comment
@HostileFork Действительно, сигнатура типа не обязательно должна быть последовательной с уравнениями, но она должна находиться в одном блоке. - person Ørjan Johansen; 27.07.2014
comment
@ØrjanJohansen Есть ли формальное определение блока Haskell, относящееся к этому? Я вижу упоминание do-block, но если вы используете исходные файлы, то какова степень детализации блока? - person HostileFork says dont trust SE; 27.07.2014
comment
@HostileFork Любопытно, что в отчете Haskell почти не используется термин «блок», говоря о layout вместо этого. Существует четыре стандартных типа блоков: where, let, do и (case) of. Первые два — это те, которые могут иметь объявления функций и тому подобное. Целый исходный файл технически является необязательным объявлением модуля, за которым следует своего рода блок where. - person Ørjan Johansen; 27.07.2014
comment
@ØrjanJohansen Достаточно интересный момент для нового вопроса, я думаю.. . - person HostileFork says dont trust SE; 27.07.2014