带中缀符号的无点样式
Point free style with infix notation
你好,在使用中缀表示法时,有没有办法写点自由风格?
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
那样截断函数的参数,但为什么不能截断运算符参数呢?
您必须将 (+)
与 (+)
组合两次,才能完全无分: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
.
当您 "leave off" 像这样来自 "end" 的多个参数时,您通常必须多次组合。研究一些类似的函数应该有助于对此建立直觉。
注意:我通常不建议在生产代码中使用这种无点(当它使事情复杂化时)。
既然你需要传递两个参数,我们可以使用所谓的“惊讶owl运算符 ”。这基本上是参数的组合。所以我们可以使用:
f = <b>((.).(.))</b> (+) (+)
或者我们可以更内联运算符,例如:
f = ((+) .) . (+)
owl运算符((.).(.)) f g
基本上是\x y -> f (g x y)
的缩写
这是如何工作的?
“惊讶 owl 运算符”的规范形式是:
= ((.) . (.))
------------- (canonical form)
(.) (.) (.)
所以我们现在可以用相应的 lambda 表达式替换 (.)
s:
(\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)
所以基本上这意味着我们惊讶的 owl 运算符等于:
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)
你好,在使用中缀表示法时,有没有办法写点自由风格?
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
那样截断函数的参数,但为什么不能截断运算符参数呢?
您必须将 (+)
与 (+)
组合两次,才能完全无分: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
.
当您 "leave off" 像这样来自 "end" 的多个参数时,您通常必须多次组合。研究一些类似的函数应该有助于对此建立直觉。
注意:我通常不建议在生产代码中使用这种无点(当它使事情复杂化时)。
既然你需要传递两个参数,我们可以使用所谓的“惊讶owl运算符 ”。这基本上是参数的组合。所以我们可以使用:
f = <b>((.).(.))</b> (+) (+)
或者我们可以更内联运算符,例如:
f = ((+) .) . (+)
owl运算符((.).(.)) f g
基本上是\x y -> f (g x y)
这是如何工作的?
“惊讶 owl 运算符”的规范形式是:
= ((.) . (.))
------------- (canonical form)
(.) (.) (.)
所以我们现在可以用相应的 lambda 表达式替换 (.)
s:
(\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)
所以基本上这意味着我们惊讶的 owl 运算符等于:
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)