你能解释一下下面的表达式是如何工作的:
str a b = ((.).(.)) (0 -) (+) 1 2
Run Code Online (Sandbox Code Playgroud)
我检查了它,GHCi说它是,-3但我不明白为什么.
我还检查了以下内容:
*Main> :t ((.).(.))
((.).(.)) :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
Run Code Online (Sandbox Code Playgroud)
但它对我没有帮助.
任何的想法?
(.).(.)有时给运营商一个别名:
(.:) = (.).(.)
Run Code Online (Sandbox Code Playgroud)
你可以查看它(.),只有当第二个函数有两个参数时它才有效.所以这有用,例如:
sqrtsum = sqrt .: (+)
-- sqrtsum 4 5 ==> 3.0
Run Code Online (Sandbox Code Playgroud)
这将取两个数字,求和,然后取总和的平方根.该.:别名排序使得视觉感,你可以想像表示两个参数的函数结肠被连接到一个参数的函数.
如果您愿意,可以查看(.)类似的类型签名:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
Run Code Online (Sandbox Code Playgroud)
这意味着它(.)需要两个函数a -> b并将b -> c它们"连接在一起"并a直接返回一个函数c.运算符的(.:)工作方式类似 - 您可以将其类型签名写为
(.:) :: (b -> c) -> (a1 -> a2 -> b) -> (a1 -> a2 -> c)
Run Code Online (Sandbox Code Playgroud)
它的作用是它需要一个函数a1 -> a2 -> b和一个函数b -> c,它会为你提供一个直接从a1和a2到达的函数c.
如果您想亲自验证此类型,您可以(.:)使用签名进行操作(.).我不会为你做这件事,部分是因为它可能最终成为一个文本墙,部分原因是因为你在推理代码时对你来说是一个很好的练习!如果你需要一个地方开始,请记住
(.) :: (b -> c) -> (a -> b) -> (a -> c)
Run Code Online (Sandbox Code Playgroud)
在表达中
(.).(.)
Run Code Online (Sandbox Code Playgroud)
也可以写成
(.) (.) (.)
Run Code Online (Sandbox Code Playgroud)
(.)(a -> b和b -> c)的两个参数函数都是它们(.)自己 - 所以你可以用它们真正代表的东西替换很多as和bs和cs!
如果您手动扩展lambda术语,您将学到最多.或者,如果你很懒,请使用工具.
无论如何,这里是:
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
Run Code Online (Sandbox Code Playgroud)
类型: (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它的值是,c并且整个函数返回,c因此-3是最终答案.