7

Let's say I have a list of functions

functions = [f, g, h]

each one with type a -> a

I also have a list of values, say numbers but anything should work here

vals = [1,2,3]

I want to apply each function in functions to the corresponding value in vals

My first instinct is to use a lambda and zipWith like:

zipWith (\f v -> f v) functions vals

But frankly this looks ugly and not something I'd expect in such a nice language like Haskell. A function application function sounds like the solution. Is there such a thing? Am I missing something and there is a much nicer solution to my problem? I actually ended-up writing this construct for a Project Euler solution. It works, but I don't like it.

Juan Pablo Santos
  • 1,200
  • 2
  • 10
  • 25

3 Answers3

16
zipWith ($) f v

$ is function application. The fact that it has particularly low precedence throws people for a loop sometimes.

Thomas M. DuBuisson
  • 64,245
  • 7
  • 109
  • 166
11

Strangely enough,

zipWith id functions vals

will work too!

But, really, zipWith ($) is the right way to write this.

MtnViewMark
  • 5,120
  • 2
  • 20
  • 29
  • 15
    @JuanPablo Because `$` is really just `id`, specialised to only work on functions (and given a very low precedence and an infix notation). The type of `$`, given that it applies a function to an argument, has to be `(a -> b) -> a -> b`. Remembering that all Haskell functions are "really" unary (or equivalently that `->` associates to the right), that the same type as `(a -> b) -> (a -> b)`. Which means it takes a function of any type and gives you a function of the same type; just a special case of `id :: a -> a` which takes a value of any type and gives you a value of the same type. – Ben Jul 31 '13 at 04:40
  • 6
    Another way to look at it: using `zipWith id` means that each resulting element is computed by `id f v`, and `id f` equals `f` so `id f v` equals `f v`. – augustss Jul 31 '13 at 08:33
3

Here's another option which might make you think a bit.

>>> import Control.Applicative
>>> let functions = ZipList [(+1), (*2), (*10)]
>>> let values    = ZipList [1, 2, 3]
>>> getZipList (functions <*> values)
[2, 4, 30]

A ZipList is just a wrapper around a list. The definition of <*> for a ZipList says "zip the list of functions (on the left) with the list of arguments (on the right) by applying each function to an argument in turn".

This is in contrast to the definition of <*> for a regular list, which says "take every possible pair of (function, argument) from these two lists and apply the function to the argument".

Chris Taylor
  • 46,912
  • 15
  • 110
  • 154