beardc
beardc

Reputation: 21063

Clarify role of list monad operator

I came across a Haskell function that tells whether a list is sorted, and I'm having trouble understanding how it works.

The code in question is

f = zipWith (<=) <*> tail

which I understand to be equivalent (in point-ful style) to

f' xs = zipWith (<=) xs (tail xs)

and as an example returns

f [4, 5, 1] == [True,False]

I take it that it has something to do with the list monad and sequential application, but would appreciate if someone could make the meaning more clear to me. What exactly is <*> doing here?

Upvotes: 6

Views: 160

Answers (2)

Sassa NF
Sassa NF

Reputation: 5406

<*> is actually from (->) a as Applicative Functor. It is a S-combinator which distributes the argument (list xs in your expansion) to two functions (zipWith (<=) and tail) in the manner that you specified in the expansion: (f <*> g) x = f x (g x).

To understand this, you need to check the type (<*>) is applied to. Since both of its arguments are a->b, we are talking about a->b as Applicative Functor - not List.

Upvotes: 7

daniel gratzer
daniel gratzer

Reputation: 53881

The <*> here isn't acting on the [a] applicative, it's acting in the (->) a applicative instance.

Essentially

 instance Applicative ((->) a) where
   pure = const -- same as monadic return
   f <*> a = \x -> f x (a x)

So it acts like function application, but also wraps the application in a function and gives the argument to both sides.

So expanding your function

 zipWith (<=) <*> tail
 \x -> zipWith (<=) x (tail x)
 \(x:xs) -> zipWith (<=) (x:xs) xs

In general it's correct to view <*> as just function application + some extra goodies. You can almost read it as whitespace!

Upvotes: 12

Related Questions