说我有功能
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
但我无法弄清楚如何做更一般的情况。
答案 0 :(得分:24)
我们有:
k x y = (f (g x)) (h y)
我们希望以无点样式编写k
。
传递给k
的第一个参数是x
。我们需要对x
做些什么?好吧,首先我们需要在其上调用g
,然后调用f
,然后执行一些想要将其应用于(h y)
的内容。
k = fancy . f . g
这是fancy
是什么?良好:
k x y = (fancy . f . g) x y
= fancy (f (g x)) y
= f (g x) (h y)
所以我们希望fancy z y = z (h y)
。减少Eta,我们得到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
k = curry ((g *** h) >>> uncurry f)
答案 1 :(得分:5)
转换
#category{
//border: thin darkgray solid;
margin: 0 auto;
margin-top: 2%;
bottom: 0;
}
.interest_categories{
border: thin darkgrey solid;
float: left;
}
.interest_categories input
{
text-align: center;
}
进入
f' x y = f (g x) (h y)
与转换流程
f' = (. h) . f . g
答案 2 :(得分:3)
这比(. h) . f. g
稍微长一些,但更容易理解。
首先,稍微重写f'
以取一个元组而不是两个参数。 (换句话说,我们原来是f'
。{/ p>
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
解决方案非常相似。)
答案 3 :(得分:3)
使用应用于(.)
函数组合运算符的“运算符节的三个规则”
(.) 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
这与answer by @chepner相同,但更简洁。
所以,你知道,你的(f.g <*> h) x
1 只是(f.g.fst <*> h.snd) (x,y)
。相同的差异。
1 (因为,对于函数,(<$>) = (.)
)
答案 4 :(得分: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