我正在学习 Haskell,虽然我很喜欢这门语言,但我发现 Pointfree 风格完全无法阅读。我遇到了下面这个只包含 ASCII 字符的函数。
f = (.)(.)
虽然我了解它的类型签名和它的作用,但我却无法理解为什么它这样做。所以,请问有人能为我写出它的非点释放版本,并且可以逐步回到点释放版本,就像这样:
f g x y = (g x) + y
f g x = (+) (g x)
f g = (+) . g
f = (.) (+)
通常而言,(?)
(其中?
代表任意中缀运算符)和\x y -> x ? y
是相同的。因此我们可以将f
重写为:
f = (\a b -> a . b) (\c d -> c . d)
现在如果我们将该参数应用于函数,我们会得到:
f = (\b -> (\c d -> c . d) . b)
现在b
只是f
的一个参数,因此我们可以将其重写为:
f b = (\c d -> c . d) . b
.
的定义是f . g = \x -> f (g x)
。如果我们用其定义替换外层的.
,那么得到:
f . g . h = (\x -> f (g x)) . h = \y -> (\x -> f (g x)) (h y) = \y -> f (g (h y))
f b = \x -> (\c d -> c . d) (b x)
我们可以再次将x
转换为普通参数:
f b x = (\c d -> c . d) (b x)
现在让我们替换另一个.
:
f b x = (\c d y -> c (d y)) (b x)
现在让我们应用这个参数:
f b x = \d y -> (b x) (d y)
现在让我们再次移动参数:
f b x d y = (b x) (d y)
完成。
(\c d -> c . d)
替换了 a
而不是 b
?我以为 Haskell 是从右到左的。 - Erik\a b -> ...
的缩写是 \a -> (\b -> ...)
. 因此,当给定一个参数 a
时,它会产生另一个期望参数 b
的函数。因此,a
首先出现。或者换句话说:给定 (\a b -> ...) 1 2
,a
将是 1
,b
将是 2
。因此,最左边的参数进入最左边的参数。 - sepp2kf a b c d = a b (c d)
= (a b) (c d)
= B (a b) c d
= B B a b c d -- writing B for (.)
所以通过 eta-contraction
f = B B
a (b c) = B a b c -- bidirectional equation
(.)
实际上是B组合子(参见BCKW组合子)。
(ab)(cd) = (ab)(I(cd))
是一个有效的转换,可能会导致其他组合子定义与之匹配。选择“最合适”的一个是一种艺术(或者是在具有相当高分支因子的搜索空间中进行搜索)。BBabcdefg = B(ab)cdefg = (ab)(cd)efg
BBabcd = B(ab)cd = (ab)(cd)
这就是全部。
f
添加参数:f = ((.) . )
f x = (.) . x
f x y = ((.) . x) y
= (.) (x y)
= ((x y) . )
f x y z = (x y) . z
f x y z t = ((x y) . z) t
= (x y) (z t)
= x y (z t)
= x y $ z t
x
和 z
其实是(分别)二元和一元函数,因此我会使用不同的标识符:f g x h y = g x (h y)
(.)
看看会得到什么结果吗? - Cubic(.)(.)
是如何形成的? - luqui