用无点样式写f?

时间:2016-08-03 12:23:56

标签: haskell pointfree

说我有功能

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  

但我无法弄清楚如何做更一般的情况。

5 个答案:

答案 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 . hfancy = (. 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)

答案 1 :(得分:5)

查看online converter

转换

 #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)

您可以使用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解决方案非常相似。)

答案 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   = (......)

Latherrinse,重复。

另一个技巧是用等式

将两个参数变成一个,反之亦然
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)

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

相关文章