我不希望这个表达式起作用:
[1,2] >>= \n -> ['a','b'] >>= \ch -> return (n,ch) -- [(1, 'a'), (1, 'b'), ...]
因为n
应该超出第二个lambda的范围。显然第二个lambda是第一个lambda的闭包:
[1,2] >>= (\n -> ['a','b'] >>= (\ch -> return (n,ch)))
我不理解的是基本规则。编译器如何决定 第二个lambda是第一个lambda的闭包,但从语法上看不出来吗?
在此表达式中,这种行为甚至毫无意义:
\x -> x + 1 . \y -> x + y
答案 0 :(得分:2)
简而言之:通常,语法正确性是编译器/解释器中的一步,在语义正确性检查(类型系统等)之前完成。有充分的理由将两者分开。
我不理解的是基本规则。编译器如何才能确定第二个lambda是第一个lambda的闭包,而从语法上看不出来呢?
Haskell编译器(就像大多数(如果不是几乎所有)所有合理的语言一样)在解析表达式时并没有明显的语义或类型系统。这是language grammar as described in the Haskell '98 report的结果。
因此,lambda表达式的主体为extends as far to the right as possible (without hitting closing parenthesis。
在此表达式中,这种行为甚至毫无意义:
\x -> x + 1 . \y -> x + y
不,也许不是。但是通常在没有类型知识的情况下进行解析。因为那将是“不稳定的”。假设您写了2 + 3 * 4
。大多数人将其视为2 + (3 * 4)
,也许某些语言会对此做出不同的解释,但最终程序员会习惯这一点。现在,假设3
是否为浮点数会导致对表达式的解释有所不同,因此2 + 3.0 * 4
突然间被解释为(2 + 3.0) * 4
。在这里,人们仍然可以说这种语言有一些明确的规则。但是如果以后再用标识符替换2
,3
和4
,那么我们真的很麻烦,因为更改该标识符的类型可能会带来完全不同的含义程序中的很多表达式。
但是通常,将lambda表达式向右扩展通常是有意义的,正如您在第一个表达式中发现的那样。例如,如果您编写:
f a b = 2 * a + b
那么这等效于:
\a -> (\b -> 2 * a + b)
或更简单:
\a -> \b -> 2 * a + b