Search code examples
haskellpointfree

pointfree add to list in haskell


I'm trying to derive function of three args, using simple function chaining.
The function should be of type

addToList :: a -> a -> a -> [a]

and be pointfree analogue of

addToList :: a b c = (a : (b : (c : [])))

So far, I've figured out

addToList = ((.)((.) (flip (:)) . (flip (:))) . (flip (:))) []

But it works in reverse:

Prelude> addToList 4 5 6
[6,5,4]

and looks bulky.

How can one get something nice like

(.) (.) (.) (:) (:) (: [])

that works as follows:

Prelude> addToList 4 5 6
[4,5,6]

?


Solution

  • Let's have a look at a more general version, that uses three functions f, g and h:

    func a b c = f a (g b (h c))
    

    In our case, f = (:), g = (:) and h = return, but we can use this for any triple of functions that follow the same scheme:

    func a b c = (f a . g b . h) c
    

    For the next step, write the first application of (.) in prefix form, so that it's easier to combine (.) (f a) and the rest later:

    func a b = (.) (f a) (g b . h)
             = (.) (f a) (g b . h)
             = (.) (f a) ((.) (g b) h)
             = (.) (f a) (flip (.) h (g b))
             = (.) (f a) ((flip (.) h . g) b)
             = (.) (f a) . (flip (.) h . g) b
    

    We can now do the same for a:

    func a = (.) (f a) . (flip (.) h . g)
           = (.) ((.) (f a)) (flip (.) h . g)
           = flip (.) (flip (.) h . g) ((.) (f a))
           = flip (.) (flip (.) h . g) . (.) (f a)
           = flip (.) (flip (.) h . g) . (.) . f a
    

    Since flip (.) x is (.x) we can get rid of flip:

    func = flip (.) (flip (.) h . g) . (.) . f
         = flip (.) ((.h) . g) . (.) . f
         = (.((.h) . g)) . (.) . f
    

    All we have to do now is to insert the definitions of f, g and h:

    func = (.((.return) . (:))) . (.) . (:)
    

    I didn't check whether there is a shorter version, but since this is the same result as pointfree.io yields, it should be more or less optimal.

    That being said, if you compare

    addToList = (.((.return) . (:))) . (.) . (:)
    

    with

    addToList a b c = [a, b, c]
    

    which one would you like to read in three months?