tags:

views:

332

answers:

7

Which of the following are you most likely to write?

r = zip xs $ map sqrt xs

or

r = [(x, sqrt x) | x <- xs]

Sample code on the Internet seems to indicate that the former is more abundant and the preferred way.

+4  A: 

I rarely use list comprehensions, but both are dandy. Just use the one that makes your code easier to read.

trinithis
+11  A: 

People who spend too much time in #haskell would probably write that as

r = map (id &&& sqrt) xs

(&&&) is a fun combinator defined in Control.Arrow. Its actual type signature is complicated because it's generalized to all instances of Arrow. But it's often used with the (->) instance of Arrow, which results in this type signature:

(&&&) :: (a -> b) -> (a -> c) -> a -> (b, c)
Carl
I refer to this as "opaque haskell".At a certain point it's just illegible, the point varies on exposure.
Dan
In fact, I tend to define a function which, for lack of a better name, I call `preserving :: (a -> b) -> a -> (a,b)`, defined as simply `preserving = (id I ought to be consistent.) I'm always a little surprised that it doesn't seem to exit anywhere standard.
Antal S-Z
Dan, I think that's probably the easiest Arrow combinator to use in real code. Its name is nicely evocative: you can read that line of code out loud as "map id and sqrt to xs".
Carl
+11  A: 

Although I tend to not use them very often, in this case, I think I'd prefer the list comprehension version, since it seems cleaner to me.

If you're into point free style, you might like this one, too:

f = zip `ap` map sqrt

ap lives in Control.Monad and in this case, it can be thought of as the S combinator, which generalizes application in SKI calculus:

ap f g x == f x (g x)
ap const const == id

As Conal points out, this may also be generalized from Monad to Applicative thusly (import Control.Applicative):

f = zip <*> map sqrt
danlei
nice, I like that notation the best. I always read `ap` as "apply", so it becomes: "zip apply map with sqrt to input"
Dan
Conal
@Dan Yes, that's IMHO a nice way to read it. @Conal added your suggestion to the answer.
danlei
+7  A: 

I would probably write map/zip and then later wish I had written the list comprehension.

Norman Ramsey
+5  A: 

For certain types of problems (Project Euler in particular), this particular case comes up so often that I wrote the following little helper:

with :: (a -> b) -> a -> (a,b)
with f a = (a, f a)

This allows your example to be written:

r = map (with sqrt) xs
MtnViewMark
+1  A: 

I'm more of an "Old School" Haskellier, so I'd use zip `ap` map sqrt and later refactor it to use the <*> instead of ap.

Applicative is the new Monad. (In the sense of "what do the Cool Haskell Kids use these days?")

BMeph
+2  A: 

I'd likely write

map (\x -> (x, sqrt x)) xs

If you prefer point-free, the above is equivalent to (after having imported Control.Monad and Control.Monad.Instances)

map (ap (,) sqrt) xs

Another alternative that hasn't yet been mentioned is

zipWith (,) xs (map sqrt xs)
Greg Bacon