List comprehensions with Applicative Functors

I just posted List comprehensions with Applicative Functors: https://bit.ly/2MDXg9i for my series Make the Leap from JavaScript to PureScript: https://bit.ly/2xc486g . It describes how Applicative Functors capture and replace the pattern of messy nested loops in imperative code.

3 Likes

Just a small comment.

You might want to explain that

pure (\x y z {- ... argN -} -> {- function body -})
<*> arg1
<*> arg2
-- ...
<*> argN

is the same as

(\x y z {- ... argN -} -> {- function body -})
<$> arg1
<*> arg2
-- ...
<*> argN

Then, when you explain the ado syntax, one understands why pure isn’t needed after the in part, regardless of the number of arguments you are passing into the function. However, I realize that doing so means you might need to explain Functor as well, so perhaps that isn’t a good idea?

You might also want to link to my code-as-an-example of Applicative Do syntax in a ‘references’ section in your post

Thanks for your comment. I covered Functor’s in previous tutorials, so if the reader has been following the series then hopefully they’re familiar with them. You make a good point - the idiomatic syntax should be f <$> a <*> b . I have an opportunity to call this out in the next tutorial, and I may go back and revise this tutorial accordingly. Thanks again!

I covered Functor’s in previous tutorials, so if the reader has been following the series then hopefully they’re familiar with them.

Nice!

I have an opportunity to call this out in the next tutorial, and I may go back and revise this tutorial accordingly.

It might help to clarify how the types align when using this idiomatic syntax. Meaning, one who understands the Functor type class’ map function might be a bit confused how a multi-arg function could be used with map and then apply.

A clear way to explain this is to desugar the -> to Function:

-- pseudo-code
type a -> b = Function a b
type a -> b -> c = Function a (Function b c)
type a -> b -> c -> d = Function a (Function b (Function c d))

-- Start
map :: (a -> b -> c -> d) -> f a -> f ?

-- desugar the first "->"
map :: Function a (b -> c -> d) -> f a -> f ?

-- fill in the "?" placeholder
map :: Function a (b -> c -> d) -> f a -> f (b -> c -> d)

-- continue the apply
apply :: f (b -> c -> d) -> f b -> f ?

-- desguar the "->"
apply :: f (Function b (c -> d)) -> f b -> f ?

-- fill in the "?" placeholder
apply :: f (Function b (c -> d)) -> f b -> f (c -> d)

-- continue the apply
apply :: f (c -> d) -> f c -> f d

-- finish:
result :: f d