Elm 如何";改为;榆树';s->;操作人员

Elm 如何";改为;榆树';s->;操作人员,elm,Elm,我真的很喜欢Elm,直到遇到一个我以前从未见过的函数,我想了解它的输入和输出 以foldl的声明为例: foldl : (a -> b -> b) -> b -> List a -> b 我看着这个,不禁觉得好像有一组括号我遗漏了,或者关于这个操作符的关联性的一些其他微妙之处(我找不到任何明确的文档)。也许这只是一个在我对它有了“感觉”之前更多地使用这种语言的问题,但我想有一种方法可以用英语“阅读”这个定义 从下面的例子来看 我希望函数签名的内容如下: 给定一个函

我真的很喜欢Elm,直到遇到一个我以前从未见过的函数,我想了解它的输入和输出

foldl
的声明为例:

foldl : (a -> b -> b) -> b -> List a -> b
我看着这个,不禁觉得好像有一组括号我遗漏了,或者关于这个操作符的关联性的一些其他微妙之处(我找不到任何明确的文档)。也许这只是一个在我对它有了“感觉”之前更多地使用这种语言的问题,但我想有一种方法可以用英语“阅读”这个定义

从下面的例子来看

我希望函数签名的内容如下:

给定一个函数,它接受一个
a
和一个
b
并返回一个
b
、一个额外的
b
、一个
列表
foldl
返回一个
b

对吗

对于像我这样迫切希望输入用逗号表示,输入/输出用逗号分隔的人,你能给他们什么建议?

简短回答 缺少括号是因为
->
是右关联的:类型
(a->b->b->List a->b
相当于
(a->b->b->(b->(List a->b))
。非正式地说,在一系列的
->
中,将最后一个
->
之前的所有内容都作为参数读取,并且只读取最右边的内容作为结果

长话短说 您可能缺少的关键洞见是——如果您有一个接受两个参数的函数,那么您可以用一个接受第一个参数并返回接受第二个参数然后返回结果的函数来表示它

例如,假设您有一个函数
add
,它接受两个整数并将它们相加。在Elm中,您可以编写一个函数,将两个元素作为元组并添加它们:

add : (Int, Int) -> Int
add (x, y) = x+y
你可以称之为

add (1, 2)  -- evaluates to 3
但是假设你没有元组。您可能认为无法编写此函数,但事实上,使用currying可以将其编写为:

add : Int -> (Int -> Int)
add x =
  let addx : Int -> Int
      addx y = x+y
  in
    addx
也就是说,您编写了一个接受
x
的函数,然后返回另一个接受
y
的函数,并将其添加到原始的
x
。你可以称之为

((add 1) 2)  -- evaluates to 3
您现在可以用两种方式来考虑
add
:要么作为一个函数,接受
x
y
并添加它们,要么作为一个“工厂”函数,接受
x
值并生成新的、专门的
addx
函数,只接受一个参数并将其添加到
x

“工厂式”的思维方式每隔一段时间就会派上用场。例如,如果您有一个名为
numbers
的数字列表,并且希望在每个数字中添加3个,那么您可以只调用
list.map(add3)numbers
;如果您编写的是元组版本,那么您就必须编写类似于
List.map(\y->add(3,y))numbers的代码,这有点尴尬

Elm源于编程语言的传统,它非常喜欢这种思考函数的方式,并在可能的情况下鼓励这种方式,因此Elm的函数语法旨在使其变得简单。为此,
->
是正确的关联:
a->b->c
相当于
a->(b->c)
。这意味着如果你不加括号,你定义的是一个函数,它接受
a
并返回
b->c
,我们同样可以把它看作是接受
a
b
并返回
c
的函数,或者相当于一个函数,它接受一个
a
并返回一个
b->c


还有另一个语法细节可以帮助调用这些函数:函数应用程序是左关联的。这样,上面的丑陋的
((add1)2)
就可以写成
add12
。通过这种语法调整,您根本不必考虑使用curry,除非您想部分应用函数——只要使用所有参数调用它,语法就会解决。

感谢您的全面响应!你能证实我的解释正确吗?下面是它似乎归结为…给定
a->b->…->n
,最后一个元素(
n
)是输出,其他所有元素都是输入。此外,任何元素本身都可以是函数。因此,在
foo:(a->b)->c->(d->e)
中,
foo
将形式为
a->b
的函数和元素
c
作为输入,并且
foo
输出形式为
d->e
的函数。是吗?@clozach:是的,是的。但请注意,在您的示例中,您可以将
d->e
视为输出,也可以将
d
视为另一个参数,将
e
视为输出,因为
->
右关联意味着
foo
的类型等效为
(a->b)->c->d->e
。好的。再次感谢。你已经回答了我最初的问题,还有一些!我将在一周左右的时间内重新审视你的答案,因为我仍然“理解”一些细节,但还没有找到答案^__^
((add 1) 2)  -- evaluates to 3