1

I had a question about one of the implementations of the duplicate function as described in 99 Haskell Questions (https://wiki.haskell.org/99_questions/Solutions/14).

One of the solutions uses the list instance of Applicative. That particular solution is

duplicate = (<**> [id,id])

I was wondering why, when I tried to implement duplicate instead as

duplicate' = ([id,id] <*>)

I get

duplicate' [1,2,3] = [1,2,3,1,2,3]

Instead of [1,1,2,2,3,3].

Thanks!

user348307
  • 21
  • 3

2 Answers2

2
[f, g] <*> [x, y]

is equivalent to

[ h w | h <- [f, g], w <- [x, y] ]

Hence, we get

[ f x, f y, g x, g y ]

By comparison

[x, y] <**> [f, g]

is equivalent to

[ h w | w <- [x, y], h <- [f, g] ]

Hence, we get

[ f x, g x, f y, g y ]

The posted example follows similarly.

Remember that applicative combinators perform the effect of the first argument first. The "effect" here is, roughly, "drawing an element from the list".

chi
  • 111,837
  • 3
  • 133
  • 218
1

f <*> v isn't the same as v <**> f. We can check this with Either:

import Control.Applicative ((<*>),(<**>))

f :: Either String (a -> b)
f = Left "f evaluated first"

v :: Either String a
v = Left "v evaluated first"

showE :: Show a => Either a b -> String
showE (Left x)  = "Left: " ++ show x
showE (Right _) = "Right"

printE = putStrLn . showE

main = do
  printE (f <*>  v)
  printE (v <**> f)

Result:

Left: "f evaluated first"
Left: "v evaluated first"

Remember, <*> sequences actions.

Zeta
  • 103,620
  • 13
  • 194
  • 236