-
Notifications
You must be signed in to change notification settings - Fork 371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Decouple Monad from Applicative #42
Comments
I added Monoid for EventStream. It already had |
This is a known issue, and Haskellers are generally unsatisfied with the current state of affairs. The Haskell situation is an artifact of monads being used in Haskell early on (to control side-effects and I/O), before applicatives were also found to be generally useful. The Monad and Applicative class instances are expected to agree even though the standard library doesn't require it. Mathematically, all monads are applicative functors by definition. I don't know Bacon.js well enough to suggest any specific alternatives. Does your |
Did you try this default definition? There may be multiple and sometimes more useful ways to write |
Guys, thanks for your replies! @markandrus My implementation of EventStream.ap is identical to the default one. If I have to choose one, I might go for the |
The issue is not whether I can implement Applicative, but more that I'd rather not because of the many different possible ways. Like, if |
@raimohanska RIght, those laws. It's best if you semi-rigorously prove that those axioms hold for your implementation, since it's easy to miss important edge cases. When I said "implement it in terms of combine/zip", I meant that there may be a Monad implementation associated with the combine/zip-based Applicative you prefer, so you may want to start there and find a new It may turn out that either of your |
Yes, Haskell stuffed up by not realising the hierarchy of Apply => Applicative => Monad. Fantasy Land doesn't have that problem. Anyway, even in Haskell, for every Monad you can get an Applicative - the opposite is of course not true. instance Monad m => Applicative (WrappedMonad m) where
pure = WrapMonad . return
WrapMonad f <*> WrapMonad v = WrapMonad (f `ap` v) Where Haskell's ap :: (Monad m) => m (a -> b) -> m a -> m b
ap = liftM2 id
liftM2 :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 f m1 m2 = do
x1 <- m1
x2 <- m2
return (f x1 x2) So if we can implement And yes, things can have multiple Applicatives. That's what I was trying to get at with this part of the spec:
Haskell does the same thing: newtype ZipList a = ZipList { getZipList :: [a] }
instance Applicative ZipList where
pure x = ZipList (repeat x)
ZipList fs <*> ZipList xs = ZipList (zipWith id fs xs) I'd say the Applicative for a data type should do the same as the Monad (if one is defined). That'd be the least surprising. Provide a wrapper for the other behaviour(s). |
An interesting feature of Applicatives is that they can not be used to change the 'control flow'. E.g. for IO (\fire -> if fire then a else b) <$> fireZeMissiles <*> petTheKoala will result in the side effects of Perhaps one could standardize on a "parallel applicative" type class, which the zip-applicative for lists and event streams could fulfill, as they are in a sense also "parallel". |
I'm closing this one, reopen if you wish to suggest other wise. |
I'm afraid it's not always correct to assume that a Monad is also an Applicative. At least I tried to implement the specs into Bacon.js today, for an excersise, and run into issues because of this assumption. I'm not sure how familiar you're with Bacon.js, but I'll try to explain the case anyway.
Now an EventStream in Bacon.js is clearly a Monadic structure: the
flatMap
method (aliased now aschain
) of EventStream has one parameter which is a function that creates a new EventStream for each value in the original stream. In combination withEventStream.of
we have a nice Monad. Except.The Applicative interface for EventStreams doesn't make much sense, at least if based on flatMap: the result stream
a.ap(b)
would take apply each function from the source stream to all (or one?) subsequent elements in the stream b. It would make more sense to baseap
oncombine
or evenzip
, but I'd rather not have EventStream implement Applicative because of this ambiguity.In Haskell, you can declare Monad without Applicative. Why not in Fantasy Land?
The fantasy-land version of Bacon.js is in the fantasy-land branch. I'm planning to bring that to master, if I can come up with a nice solution. The current EventStream/Applicative one seems to be compliant, but I would never use it because Applicative through flatMap just makes no sense.
I'd like to have EventStream implement Functor and Monad (no Applicative), and Property implement Functor and Applicative (and a Duck Monad (Property.flatMap returns an instance of EventStream)).
Please ask for more details if this made no sense to you :)
The text was updated successfully, but these errors were encountered: