Скомпилировано или интерпретировано: разрешить или не разрешить

Почему интерпретатору Haskell (GHCI 7.10.3) нужны определения функций в выражении let, но компилятор Haskell (GHC 7.10.3) выдает ошибку парсера, если определение функции находится внутри выражения let?

Я прорабатываю «Learn You a Haskell for Great Good!» Первая функция ребенка - doubleMe: doubleMe x = x + x

Почему интерпретатор принимает это определение, если оно находится в выражении let, а в противном случае выдает ошибку синтаксического анализа при вводе '='? Между тем, если я компилирую ту же функцию из файла, почему GHC выдает ошибку синтаксического анализа, если определение функции находится в выражении let, и компилирует определение, если оно не входит в выражение let? Исходя из опыта работы с Lisp, я удивлен, что интерактивный Haskell, а также загрузка и компиляция файлов Haskell по-разному трактует эти определения.


person fpt    schedule 17.10.2016    source источник
comment
Это условность. Если бы GHCi работал точно так же, как запись в файле .hs, запись 1+1 была бы ошибкой, как и print (2,3). Вместо этого GCHi решил использовать небольшое волшебство, чтобы принять как эти выражения, так и let определения. О том, почему x=1 без let отклоняется - я не думаю, что есть четкий ответ на этот вопрос, за исключением того, что для этого потребуется больше магии.   -  person chi    schedule 17.10.2016
comment
Правильно. FWIW, IHaskell позволяет смешивать оба стиля.   -  person leftaroundabout    schedule 17.10.2016
comment
Самая новая версия GHCi (8.0.1) принимает doubleMe x = x + x. Достаточно людей вроде вас жаловались, что добавили для этого особый случай. :)   -  person Alec    schedule 17.10.2016
comment
Это фундаментальное различие, которое я сейчас ценю между Haskell и Lisp: интерактивный доступ к компилятору через командную строку и интерактивный доступ к самому языку через REPL, соответственно.   -  person fpt    schedule 17.10.2016


Ответы (3)


Причина этого в том, что GHCi (в 7.10.3) ожидает только в командной строке

Если это кажется вам неожиданным, помните, что оценка Lisp и Haskell сильно отличается - Lisp просто интерпретируется, пока Haskell компилируется.

Как вы понимаете, определения верхнего уровня не входят в этот список. К счастью, это было исправлено в GHCi 8.0.1, который теперь поддерживает необработанные объявления функций верхнего уровня. Следующие работы (в 8.0.1):

ghci> doubleMe x = x + x
ghci> doubleMe 1
2
person Alec    schedule 17.10.2016
comment
Это не имеет ничего общего с компиляцией и интерпретацией. Я считаю, что на самом деле скомпилировано много Лиспа, хотя я думаю, что Scheme может быть единственным Лиспом, который действительно разработан для хорошей компиляции. - person dfeuer; 17.10.2016
comment
Я подозреваю, что настоящая мотивация для отказа от включения этой функции в ранние версии ghci - это удивительное поведение, например, maybeDoubleMe Nothing = Nothing\nmaybeDoubleMe (Just x) = Just (x+x) в ghci по сравнению с файлом. - person Daniel Wagner; 18.10.2016

Командная строка интерпретатора GHCi обрабатывает ввод, как если бы он был в предложении do. Итак, вы можете ввести это:

:module + System.Random
v <- getStdRandom $ randomR (1,10)

Если не считать директивы :module, это именно то, что было бы в предложении do.

Таким же образом вы можете написать

let f x = 2 * x

потому что именно так это было бы в предложении do.

person Paul Johnson    schedule 17.10.2016

Реализации современного Лиспа компилируются в машинный код, часто по умолчанию, даже когда код вводится в командной строке. Приглашение Lisp - это не просто место для ввода команд, это место для взаимодействия с языком, потому что весь язык становится доступным с помощью цикла Read-Evaluate-Print. Это означает, что Lisp считывает текст в символьные выражения, которые затем оценивает, распечатывая любой вывод на печать и любые возвращаемые значения. Например,

? (defun a-fun () nil)
A-FUN
? (compiled-function-p #'a-fun)
T

Compiled-Function-P Clozure Common Lisp

В Лиспе код, который вы можете ввести в образ Лиспа, скомпилировав и загрузив файл, вы также можете войти в образ Лиспа, набрав его в REPL. Оказалось, что я был удивлен, потому что ожидал, что приглашение GHCi будет REPL, но, как описывает @Alec, это не так. потому что он не считывает текст в выражения Haskell, который затем оценивал бы, как это делает Lisp. Как говорит @dfeuer, проблема не в компиляции или интерпретации. Проблема в том, что приглашение GHCi предлагает ограниченное взаимодействие с компилятором Haskell, а не взаимодействие с самим Haskell, как это делает REPL в Lisp.

person fpt    schedule 17.10.2016