您能解释一下以下表达式的工作原理:
str a b = ((.).(.)) (0 -) (+) 1 2
我检查了一下,GHCi说它是-3
,但我不明白为什么。
我还检查了以下内容:
*Main> :t ((.).(.))
((.).(.)) :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
但它没有帮助我。
有什么想法吗?
答案 0 :(得分:9)
运算符(.).(.)
有时会被赋予别名:
(.:) = (.).(.)
您可以将其视为(.)
,只有在第二个函数接受两个参数时才有效。所以这有用,例如:
sqrtsum = sqrt .: (+)
-- sqrtsum 4 5 ==> 3.0
这将取两个数字,求它们然后取总和的平方根。 .:
别名有点视觉,你可以想象冒号表示两个参数的函数连接到一个参数的函数。
如果您愿意,可以像这样查看(.)
的类型签名:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
这意味着(.)
需要两个函数a -> b
和b -> c
并“将它们组合在一起”并从a
直接向c
返回一个函数。运算符(.:)
的工作方式类似 - 您可以将其类型签名写为
(.:) :: (b -> c) -> (a1 -> a2 -> b) -> (a1 -> a2 -> c)
它的作用是它需要一个函数a1 -> a2 -> b
和一个函数b -> c
,它会为您提供一个直接从a1
和a2
到{{ 1}}。
如果您想亲自验证此类型,可以使用c
的签名前往(.:)
。我不会为你做这件事,部分原因是因为它可能最终成为一个文本墙,部分原因是因为在推理你的代码时这对你来说是一个很好的练习!如果你需要一个地方开始,请记住
(.)
在表达式
中(.) :: (b -> c) -> (a -> b) -> (a -> c)
也可以写成
(.).(.)
(.) (.) (.)
((.)
和a -> b
)的两个参数函数本身都是b -> c
- 所以你可以替换很多(.)
和a
和b
以及它们真正代表的内容!
答案 1 :(得分:8)
如果您手动扩展lambda术语,您将学到最多。或者,如果您懒惰,请使用tool。
无论如何,这是:
dot = λf.λg.λx.f (g x)
dot dot dot (0 -) + 1 2
⇒ (λg.λx.dot (g x)) dot (0 -) + 1 2
⇒ (λx.dot (dot x)) (0 -) + 1 2
⇒ dot (dot (0 -)) + 1 2
⇒ (λg.λx.dot (0 -) (g x)) + 1 2
⇒ (λx.dot (0 -) (+ x)) 1 2
⇒ dot (0 -) (+ 1) 2
⇒ (λg.λx.0 - (g x)) (+ 1) 2
⇒ (λx.0 - (+ 1 x)) 2
⇒ 0 - (+ 1 2)
⇒ 0 - 3
答案 2 :(得分:7)
类型:(b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
值:(0 -)_______(+)_______________1___2
1为a
,2为a1
,(+)
为(a -> a1 -> b)
..将(+)
应用于1和2,您获得3,现在为b
。
(0 -)
为(b -> c)
,对此应用3(上面为b
),您将获得(0-3)即-3
,其值为{{1}并且整个函数返回c
因此-3是最终答案。