为什么Haskell解释器(GHCI 7.10.3)需要函数定义在let表达式中,但如果函数定义在let表达式中,Haskell编译器(GHC 7.10.3)会抛出解析器错误?
我正在通过“Learn You a Haskell for Great Good!”宝贝的第一个功能是doubleMe: doubleMe x = x + x
为什么解释器接受这个定义,如果它在let表达式中,否则在输入'='上抛出一个解析错误?同时,如果我正在从文件中编译相同的函数,为什么GHC会抛出一个解析错误,如果函数定义在let表达式中并且如果它不在let表达式中则编译定义?来自Lisp背景,我很惊讶交互式Haskell和文件加载和编译Haskell以不同的方式处理这些定义。
答案 0 :(得分:4)
这背后的原因是GHCi(在7.10.3中)只在提示时预期
:h
列出可用的命令)data
,type
,newtype
,class
,instance
,deriving
和{{ 1}}但不常规定义)foreign
或1+1
)do
statments(例如let x = 3 in x*x
或print "hi"
或 x <- getLine
)如果这对您来说似乎很惊讶,请记住Lisp和Haskell的评估是非常不同的 - Lisp只是被解释,而Haskell正在被编译。
如您所知,顶级定义不是此列表的一部分。值得庆幸的是,这已在GHCi 8.0.1中得到修复,它现在支持原始顶级函数声明。以下工作(在8.0.1中):
let doubleMe x = x + x
答案 1 :(得分:3)
GHCi解释器命令行将其输入视为do
子句中的输入。所以你可以输入:
:module + System.Random
v <- getStdRandom $ randomR (1,10)
除:module
指令外,这正是do
子句中的指示。
同样你可以写
let f x = 2 * x
因为这就是do
子句中的含义。
答案 2 :(得分:0)
Modern Lisp实现编译为本机代码,通常默认情况下即使在提示符下输入代码也是如此。 Lisp的提示不仅仅是一个输入命令的地方,它是一个与语言交互的地方,因为Read-Evaluate-Print Loop提供了整个语言。这意味着Lisp将文本读入符号表达式,然后进行评估,打印任何打印输出和任何返回值。例如,
? (defun a-fun () nil)
A-FUN
? (compiled-function-p #'a-fun)
T
Compiled-Function-P Clozure Common Lisp
使用Lisp代码,你可以通过编译和加载文件进入Lisp图像,你也可以通过在REPL输入来输入Lisp图像。所以事实证明我很惊讶,因为我期望GHCi提示符是一个REPL,但正如@Alec描述的那样,并不是因为它不会将文本读入Haskell表达式,然后它会像Lisp那样进行评估。正如@dfeuer所说,问题不在于编译与解释。问题是GHCi的提示提供了与Haskell编译器的有限交互,而不是像Lisp的REPL那样与Haskell本身进行交互。