Write f in pointfree-style?

风格不统一 提交于 2019-12-10 09:21:09

问题


Say I have functions

g :: a -> b, h :: a -> c 

and

f :: b -> c -> d. 

Is it possible to write the function

 f' :: a -> a -> d 

given by

f' x y = f (g x) (h y) 

in point free style?.

One can write the function

f' a -> d, f' x = f (g x) (h x) 

in point free style by setting

f' = (f <$> g) <*> h  

but I couldn't figure out how to do the more general case.


回答1:


We have:

k x y = (f (g x)) (h y)

and we wish to write k in point-free style.

The first argument passed to k is x. What do we need to do with x? Well, first we need to call g on it, and then f, and then do something fancy to apply this to (h y).

k = fancy . f . g

What is this fancy? Well:

k x y = (fancy . f . g) x y
      = fancy (f (g x)) y
      = f (g x) (h y)

So we desire fancy z y = z (h y). Eta-reducing, we get fancy z = z . h, or fancy = (. h).

k = (. h) . f . g

A more natural way to think about it might be

                             ┌───┐           ┌───┐
                        x ───│ g │─── g x ───│   │
                      /      └───┘           │   │
               (x, y)                        │ f │─── f (g x) (h y)
                      \      ┌───┐           │   │
                        y ───│ h │─── h y ───│   │
                             └───┘           └───┘

                      └──────────────────────────────┘
                                      k

Enter Control.Arrow:

k = curry ((g *** h) >>> uncurry f)



回答2:


Take a look at online converter

It converted

f' x y = f (g x) (h y) 

into

f' = (. h) . f . g

with the flow of transformations

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



回答3:


This is slightly longer, but a little easier to follow, than (. h) . f. g.

First, rewrite f' slightly to take a tuple instead of two arguments. (In otherwords, we're uncurrying your original f'.)

f' (x, y) = f (g x) (h y)

You can pull a tuple apart with fst and snd instead of pattern matching on it:

f' t = f (g (fst t)) (h (snd t))

Using function composition, the above becomes

f' t = f ((g . fst) t) ((h . snd) t)

which, hey, looks a lot like the version you could make point-free using applicative style:

f' = let g' = g . fst
         h' = h . snd
     in (f <$> g') <*> h'

The only problem left is that f' :: (a, a) -> d. You can fix this by explicitly currying it:

f' :: a -> a -> d
f' = let g' = g . fst
         h' = h . snd
     in curry $ (f <$> g') <*> h'

(This is very similar, by the way, to the Control.Arrow solution added by Lynn.)




回答4:


Using the "three rules of operator sections" as applied to the (.) function composition operator,

(.) f g  =  (f . g)  =  (f .) g  =  (. g) f   -- the argument goes into the free slot
--       1           2           3

this is derivable by a few straightforward mechanical steps:

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

Lastly, (.) is associative, so the inner parens may be dropped.

The general procedure is to strive to reach the situation where eta-reduction can be performed, i.e. we can get rid of the arguments if they are in same order and are outside any parentheses:

k x y = (......) y
=>
k x   = (......)

Lather, rinse, repeat.


Another trick is to turn two arguments into one, or vice versa, with the equation

curry f x y = f (x,y)     

so, your

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

This is the same as the answer by @chepner, but presented more concisely.

So, you see, your (f.g <*> h) x1 just becomes (f.g.fst <*> h.snd) (x,y). Same difference.


1(because, for functions, (<$>) = (.))




回答5:


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

Related articles

  • Semantic Editor Combinators, Conal Elliott, 2008/11/24
  • Pointless fun, Matt Hellige, 2008/12/03


来源:https://stackoverflow.com/questions/38743576/write-f-in-pointfree-style

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!