13

I started with haskell yesterday and am still completely lost on the shore of this brave new world. Now I have run into the following issue:

Let's assume I have some function that does some magic to an integer and another variable:

makeTuple :: Int -> a -> (Int, a)
makeTuple n x = (n, x)

Now I want to apply this function to all elements of a list. So far no problem, as mapping is your daily bread and butter in python (where I come from), too.

makeTupleList :: Int -> [a] -> [ (Int, a) ]
makeTupleList n x = map (makeTuple n) x

As far as I understand, the binary function makeTuple is applied partially with the integer n and hence becomes a unary function which can be mapped to each element of x. So far, all is well.

But what do I do when the makeTuple function has another signature, like:

makeTuple2 :: a -> Int -> (Int, a)
makeTuple2 x n = (n, x)

Many ways lead to Rome: the effect is the same, but the way is another. Now obviously the mapping doesn't work anymore: The function expects an Int and gets an a.

makeTupleList2 :: Int -> [a] -> [ (Int, a) ]
makeTupleList2 n x = map (makeTuple2 n) x -- boolshit

This was to be expected. My -maybe too pythonic- workaround is using another function to pass the parameters where they should go:

makeTupleList2 :: Int -> [a] -> [ (Int, a) ]
makeTupleList2 n x = map (\x -> makeTuple2 x n) x

Question: What is the preferred functional, haskell-style way of partially applying functions when the parially applied parameters isn't the leftmost?

duplode
  • 33,731
  • 7
  • 79
  • 150
Hyperboreus
  • 31,997
  • 9
  • 47
  • 87

4 Answers4

16

You can use flip, which swaps the first and second arguments of a function.

makeTupleList2 n x = map (flip makeTuple2 n) x

Another option is to use the backticks syntax to make an infix operator and then partially apply that using an operator section.

maleTupleList2 n x = map (`makeTuple2` n) x

Or, as you said we can use a lambda expression. Which one to use depends on context and personal taste. Use whatever you feel is most clear.


PS: What you're doing is called partial application. Currying is the process of transforming a function taking multiple arguments (a, b) -> c into curried form a -> b -> c so that it can be partially applied.

hammar
  • 138,522
  • 17
  • 304
  • 385
  • I think there is a mistake in terminology here. Backticks convert function to an infix operator. Partial application is then performed using the operator section syntax. Backticks have nothing to do with operator section otherwise. – Rotsor Jul 16 '11 at 19:50
1

You can replace \x -> makeTuple2 x n with flip makeTuple2 n, because the Prelude defines flip like: (my implementation, not theirs)

flip :: (a -> b -> c) -> b -> a -> c
flip f y x = f x y

Hence we get

makeTupleList2' = map . flip makeTuple2

Or, seeing as how its just a tuple:

makeTupleList2'' = map . (,)

Also note (I'm not sure how efficient this is), you could use zip:

makeTupleList2''' :: a -> [b] -> [(a, b)]
makeTupleList2''' = zip . repeat
alternative
  • 12,703
  • 5
  • 41
  • 41
1

In this particular case you could use flip makeTuple2 n, but that only works for functions with two arguments. But generally, I don't find your solution with the lambda un-haskelly or too pythonic.

bzn
  • 2,362
  • 1
  • 17
  • 20
  • Actually, suppose in the type of `flip` we substitute `c = d -> e` to get `(a -> b -> d -> e) -> b -> a -> d -> e`. This can be handy if you want a point-free function with more than one parameter. That is, you want to call `flip f b'` and have two point-free parameters. – alternative Jul 16 '11 at 14:44
  • 1
    More generally, we can define the function `$(rotate n)` where n is the number of parameters, to be analagous to `flip`, by rotating the parameters (I'm not sure if `rotate` is definable via typeclass recursion) – alternative Jul 16 '11 at 14:49
  • @camccann Ahh, neat. I never actually tried to define it myself. – alternative Jul 16 '11 at 19:08
1

If your functions are only tuple constructors:

makeTuple x y = (x,y)

(which can also be written as makeTuple = (,)) then there is a special extension for this:

{-# LANGUAGE TupleSections #-}
makeTupleList2 n x = map (n,) x
makeTupleList2' n x = map (,n) x     -- Use n as the second component

which can also be written as

makeTupleList2 n = map (n,)
makeTupleList2' n = map (,n)

Otherwise use ways already suggested.

sdcvvc
  • 25,343
  • 4
  • 66
  • 102