繁体   English   中英

用无点样式写f?

[英]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)

你可以用fstsnd分开一个元组而不是模式匹配:

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

这与@chepner答案相同,但更简洁。

所以,你看,你的(fg <*> h) x 1变成了(fgfst <*> h.snd) (x,y) 相同的区别。


1 (因为,对于函数, (<$>) = (.)

Control.Compose

(g ~> h ~> id) f

Data.Function.Meld

f $* g $$ h *$ id

Data.Function.Tacit

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM