使用中缀表示法时,有没有办法写点免费样式?
f::Int->Int->Int->Int
f a b=(+) (a+b)
为什么你不能做这样的事情?
f::Int->Int->Int->Int
f a b=(a+b) +
or
f a b= (a+b) `+`
你能不能像点那样组合点自由风格的运算符吗?
ptfree::Int->Int->Int->Int
ptfree=(+) (+)
我的意思是你可以删除像fold
这样的函数的参数,但为什么不对运算符参数?
答案 0 :(得分:3)
您必须将(+)
与f = ((+) .) . (+)
一起撰写两次,以使其完全无点:(f . g) x = f (g x)
回想一下,作文被定义为
(f . g) = \x -> f (g x)
或等同于:
f = ((+) .) . (+)
因此,如果您查看合成(.)
并使用f = ((+) .) . (+)
f = \x -> ((+) .) ((+) x) -- definition of (.)
f = \y -> (\x -> (+) (((+) x) y)) -- definition of (.)
f x y = (+) (((+) x) y) -- a simpler way to write this
f x y z = (+) (((+) x) y) z -- explicitly add in the final argument (eta expansion)
f x y z = ((+) x y) + z -- rewrite as infix
f x y z = (x + y) + z -- rewrite as infix
的定义向后工作:
f
你知道我们在尝试使它成为无点之前我们最终得到了什么,所以我们知道这个定义是有效的。从上面的步骤开始,大致从下到上,可以让您了解如何找到像toy
这样的函数的无点定义。
当你像这样从“结束”“离开”多个参数时,你通常必须多次复合。通过一些类似的功能应该有助于为此建立直觉。
注意:我一般不建议在生产代码中使用这种无点(当它使事情变得复杂时)。
答案 1 :(得分:3)
因为你需要传递两个参数,我们可以使用所谓的“惊讶的猫头鹰操作符”。这基本上是参数的组合。所以我们可以使用:
f = ((.).(.)) (+) (+)
或者我们可以更像内联运营商:
f = ((+) .) . (+)
猫头鹰操作符((.).(.)) f g
基本上是\x y -> f (g x y)
这是如何运作的?
“惊讶的猫头鹰操作员”的规范形式是:
= ((.) . (.))
------------- (canonical form)
(.) (.) (.)
所以我们现在可以用相应的lambda表达式替换(.)
:
(\f g x -> f (g x)) (.) (.)
现在我们可以执行一些替换:
(\f g x -> f (g x)) (.) (.)
-> (\x -> (.) ((.) x))
-> (\x -> (\q r y -> q (r y)) ((.) x))
-> (\x -> (\r y -> ((.) x) (r y)))
-> (\x r y -> ((.) x) (r y))
-> (\x r y -> ((\s t u -> s (t u)) x) (r y))
-> (\x r y -> (\t u -> x (t u)) (r y))
-> (\x r y -> (\u -> x ((r y) u)))
-> \x r y u -> x ((r y) u))
-> \x r y u -> x (r y u)
所以基本上它意味着我们惊讶的猫头鹰操作员,等于:
surprised_owl :: (y -> z) -> (a -> b -> y) -> a -> b -> z
surprised_owl f g x y = f (g x y) -- renamed variables
如果我们现在专注于提供的功能(两次(+)
),我们得到:
f = surprised_owl (+) (+)
这样:
f x y = (+) ((+) x y)