Live data from Hacker News

Applicative WTF?

blog.plover.com

11–20 of 31 posts

Re: Applicative WTF?

#12
post #10
post #8

The reason GHC won't infer the definition of Applicative is because there can be multiple valid `Applicative` instances for a type (unlike `Functor` where there is a unique (non-trivial) instance). The canonical example of this is lists, with 2 valid instances of `Applicative`. The author of the post seems to have this realization, but I wanted to call it out, just in case.

That's true, but only one of the instances is 'compatible' with the Monad definition which requires ( ) = ap (the first 'recipe' he showed for implementing Applicative)

I think that law is slightly too restrictive; there’s a useful class of Monad instances where it doesn’t hold: commutative monads, in which:

    x 
Is equal to:

    y 
Provided that “x” is not free in “g”. A good example is an async monad that provides concurrency in () and only blocks when there’s a data dependency in (>>=)—the result is the same regardless of evaluation order, but the implementations (and performance characteristics) are different. You could handwave it away by arguing that they’re “morally equivalent”, but I think it pays to be precise about properties like commutativity of actions.

Re: Applicative WTF?

#13
It seems to me that people often overthink applicative. It falls right out of functor. Normally when you call fmap, you pass it a function that takes a single parameter. What happens if you pass it a function that takes more than one parameter (the other parameters being curried)? fmap applies a value from the functor to the function. Since it only passes one parameter, the result is a partially applied function. The result is that you end up with a functor containing partially applied functions.

For example, take a list of number and a function that takes 2 parameters, x and y. Maybe the function adds x to y (it doesn't matter). Pass these to fmap. Your result will be a list of partially applied functions with x being set to the values in the list. Now we want to apply the y parameter. We need something similar to fmap, but rather than taking a function and a functor, it needs to take a functor containing functions and a functor containing data. It will then apply the data to the functions and you will end up with a functor containing the result.

That's all applicative is. It applies the subsequent parameters to the result of having run fmap on functions that have more than one parameter. It shows up in a lot of different places, though and is incredibly handy. When I'm writing FP style code in languages that don't normally curry parameters, I often find myself currying parameters precisely because I want applicative ;-). It's just super convenient.

NB: pure being part of applicative is really interesting. I don't know for sure, but I'm relatively sure that a functor is applicative IFF your can define pure for it, which is really interesting to think about.

Edit: weird wording

Re: Applicative WTF?

#14
post #2

> Last time I used Haskell, Applicative wasn't even a thing. I had read the McBride and Paterson paper that introduced applicative functors, but that was years ago, and I didn't remember any of the details. In the previous post he learns how to use an Applicative. In this post, he learns how to define Applicative for a new type he's created. Yes, Applicative is abstract enough that it takes a few concrete examples to…

Yet another reason why learning Algorithms + Data Structures + Paradigms is much more powerful than focusing too much on language specifics.

Re: Applicative WTF?

#15
post #10

Earlier quoted context omitted.

That's true, but only one of the instances is 'compatible' with the Monad definition which requires ( ) = ap (the first 'recipe' he showed for implementing Applicative)

I think that law is slightly too restrictive; there’s a useful class of Monad instances where it doesn’t hold: commutative monads, in which: x Is equal to: y Provided that “x” is not free in “g”. A good example is an async monad that provides concurrency in ( ) and only blocks when there’s a data dependency in (>>=)—the result is the same regardless of evaluation order, but the implementations (and performance charac…

> the result is the same regardless of evaluation order, but the implementations (and performance characteristics) are different. You could handwave it away by arguing that they’re “morally equivalent”, but I think it pays to be precise about properties like commutativity of actions.

You have to decide whether they're equivalent or they're not, and if they're not equivalent (for your purposes) you probably shouldn't provide both instances. If you implement and ap but they're not equivalent, a future maintainer will get a nasty surprise sooner or later.

Re: Applicative WTF?

#16
I find it a little easier to decide what the Applicative instance "should" do by starting with

pair :: f a -> f b -> f (a, b)

from which you can derive the rest using pure and fmap

Re: Applicative WTF?

#17
post #7
post #5

Earlier quoted context omitted.

Right It is interesting that he knew this fact,and that it would be nice if this code could be automatically derived too, but I think that should not replace the learning process. It is more of a nit for advanced users

Indeed, the learning process is important. I think it's particularly instructive to look at how `ap` is implemented, and what is left out in the transition from Monad to Applicative: mf `ap` ma = do f With a Monad, the action on the right of the bind operator is a function of the result of the action on the left. The second operand of the `ap` function, however, does not have any access to the result of the first ope…

Does this mean that many Monads have two possible Applicative instances? For the two orders of "running" mf and ma?

Re: Applicative WTF?

#18

It seems to me that people often overthink applicative. It falls right out of functor. Normally when you call fmap, you pass it a function that takes a single parameter. What happens if you pass it a function that takes more than one parameter (the other parameters being curried)? fmap applies a value from the functor to the function. Since it only passes one parameter, the result is a partially applied function. The…

That's a great explanation. This is similar to the post's example with tree of functions tree of values = tree of results.

Re: Applicative WTF?

#19

It seems to me that people often overthink applicative. It falls right out of functor. Normally when you call fmap, you pass it a function that takes a single parameter. What happens if you pass it a function that takes more than one parameter (the other parameters being curried)? fmap applies a value from the functor to the function. Since it only passes one parameter, the result is a partially applied function. The…

[deleted]

Re: Applicative WTF?

#20

It seems to me that people often overthink applicative. It falls right out of functor. Normally when you call fmap, you pass it a function that takes a single parameter. What happens if you pass it a function that takes more than one parameter (the other parameters being curried)? fmap applies a value from the functor to the function. Since it only passes one parameter, the result is a partially applied function. The…

> It seems to me that people often overthink applicative. It falls right out of functor. Normally when you call fmap, you pass it a function that takes a single parameter. What happens if you pass it a function that takes more than one parameter (the other parameters being curried)? fmap applies a value from the functor to the function. Since it only passes one parameter, the result is a partially applied function. The result is that you end up with a functor containing partially applied functions.

I blame this on Haskell's overreliance on currying. If applicative was explained in terms of (pure and) liftA2 aka map2, which is completely equivalent to defining it in terms of ap, the analogy with Functor would be much more obvious.

> NB: pure being part of applicative is really interesting. I don't know for sure, but I'm relatively sure that a functor is applicative IFF your can define pure for it, which is really interesting to think about.

Not true. Const b (i.e. f a = b for all a) forms a valid functor and you can define pure as long as there's at least one value of type b (pure a = 1 where 1 is that value), but if b is some type that does not form a monoid (e.g. nonzero octonions) then Const b does not from an applicative.

Post reply on HN