[英]Write f in pointfree-style?
说我有功能
g :: a -> b, h :: a -> c
和
f :: b -> c -> d.
是否可以编写该功能
f' :: a -> a -> d
由...给出
f' x y = f (g x) (h y)
点自由风格?
可以写这个功能
f' a -> d, f' x = f (g x) (h x)
通过设置点自由风格
f' = (f <$> g) <*> h
但我无法弄清楚如何做更一般的情况。
我们有:
k x y = (f (g x)) (h y)
我们希望以无点的方式写k
。
传递给k
的第一个参数是x
。 我们需要用x
做什么? 好吧,首先我们需要在它上面调用g
,然后调用f
,然后做一些花哨的事情来将它应用于(hy)
。
k = fancy . f . g
这是什么fancy
? 好:
k x y = (fancy . f . g) x y
= fancy (f (g x)) y
= f (g x) (h y)
所以我们希望fancy zy = z (hy)
。 Eta减少,我们得到fancy z = z . h
fancy z = z . h
,或fancy = (. h)
。
k = (. h) . f . g
考虑它的更自然的方式可能是
┌───┐ ┌───┐
x ───│ g │─── g x ───│ │
/ └───┘ │ │
(x, y) │ f │─── f (g x) (h y)
\ ┌───┐ │ │
y ───│ h │─── h y ───│ │
└───┘ └───┘
└──────────────────────────────┘
k
输入Control.Arrow
:
k = curry ((g *** h) >>> uncurry f)
看看在线转换器
它转换了
f' x y = f (g x) (h y)
成
f' = (. h) . f . g
随着变换的流动
f' = id (fix (const (flip ((.) . f . g) h)))
f' = fix (const (flip ((.) . f . g) h))
f' = fix (const ((. h) . f . g))
f' = (. h) . f . g
这比(. h) . f. g
略长,但更容易理解(. h) . f. g
(. h) . f. g
(. h) . f. g
。
首先,稍微重写f'
以取一个元组而不是两个参数。 (换句话说,我们没有理解你的原始f'
。)
f' (x, y) = f (g x) (h y)
你可以用fst
和snd
分开一个元组而不是模式匹配:
f' t = f (g (fst t)) (h (snd t))
使用功能组合,以上变为
f' t = f ((g . fst) t) ((h . snd) t)
哪,嘿,看起来很像你可以使用应用风格无点的版本:
f' = let g' = g . fst
h' = h . snd
in (f <$> g') <*> h'
剩下的唯一问题是f' :: (a, a) -> d
。 你可以通过明确地解决它来解决这个问题:
f' :: a -> a -> d
f' = let g' = g . fst
h' = h . snd
in curry $ (f <$> g') <*> h'
(顺便说一句,这与Lynn添加的Control.Arrow
解决方案非常相似。)
使用应用于(.)
函数组合运算符的“运算符部分的三个规则”,
(.) f g = (f . g) = (f .) g = (. g) f -- the argument goes into the free slot
-- 1 2 3
这可以通过一些简单的机械步骤推导出来:
k x y = (f (g x)) (h y) -- a (b c) === (a . b) c
= (f (g x) . h) y
= (. h) (f (g x)) y
= (. h) ((f . g) x) y
= ((. h) . (f . g)) x y
最后, (.)
是关联的,因此可以删除内部的parens。
一般程序是努力达到可以执行eta减少的情况,即如果它们的顺序相同并且在任何括号之外,我们可以摆脱它们:
k x y = (......) y
=>
k x = (......)
另一个技巧是用等式将两个参数变成一个,反之亦然
curry f x y = f (x,y)
所以,你的
f (g x) (h y) = (f.g) x (h y) -- by B-combinator rule
= (f.g.fst) (x,y) ((h.snd) (x,y))
= (f.g.fst <*> h.snd) (x,y) -- by S-combinator rule
= curry (f.g.fst <*> h.snd) x y
所以,你看,你的(fg <*> h) x
1变成了(fgfst <*> h.snd) (x,y)
。 相同的区别。
1 (因为,对于函数, (<$>) = (.)
)
(g ~> h ~> id) f
f $* g $$ h *$ id
lurryA @N2 (f <$> (g <$> _1) <*> (h <$> _2))
lurryA @N5 (_1 <*> (_2 <*> _4) <*> (_3 <*> _5)) f g h
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.