0

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]

?

Agnis
  • 25
  • 3
  • 1
    You could simply use [pointfree.io](http://pointfree.io/) which yields: `addToList = (. ((. return) . (:))) . (.) . (:)` – Bakuriu Mar 08 '16 at 10:33
  • 6
    And that's so much more clear than `addToList a b c = [a,b,c]`. \*sigh\* – Zeta Mar 08 '16 at 10:35

2 Answers2

3

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?

Zeta
  • 103,620
  • 13
  • 194
  • 236
0

Just playing with this a little, maybe it will give you some ideas...

-- | >>> append [4,5] 6
-- [4,5,6]
append :: [a] -> a -> [a]
append = flip (flip (++) . (: []))

-- | >>> f1 4
-- [4]
f1 :: a -> [a]
f1 = (:[])

-- | >>> f2 4 5
-- [4,5]
f2 :: a -> a -> [a]
f2 = append . f1

-- | >>> f3 4 5 6
-- [4,5,6]
f3 :: a -> a -> a -> [a]
f3 = (append .) . f2

-- | >>> f4 4 5 6 7
-- [4,5,6,7]
f4 :: a -> a -> a -> a -> [a]
f4 = ((append .) .) . f3
Chris Martin
  • 30,334
  • 10
  • 78
  • 137