Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
428 views
in Technique[技术] by (71.8m points)

haskell - Why is ap available inside Applicative?

I am trying to implement MonadUnliftIO for Snap and analyzing Snap classes. I discovered that ap is used for implementing Applicative while ap requires Monad and Monad requires Applicative. It looks like a loop.

I thought till now that is not possible to write such things. What is the limit for such kind of trick?


class Functor f => Applicative f where
  pure :: a -> f a
  (<*>) :: f (a -> b) -> f a -> f b

class Applicative m => Monad m where
  return :: a -> m a
 
instance Applicative Snap where
  pure x = ...
  (<*>) = ap

ap :: Monad m => m (a -> b) -> m a -> m b

question from:https://stackoverflow.com/questions/65843114/why-is-ap-available-inside-applicative

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

This only works because Snap has a Monad instance (and it's actually in scope at that point).

Effectively, the compiler handles declarations in two separate passes: first it resolves all the instance heads

instance Applicative Snap
instance Monad Snap

...without even looking in the actual method implementations. This works out fine: Monad is happy as long as it sees the Applicative instance.

So then it already knows that Snap is a monad. Then it proceeds to typecheck the (<*>) implementation, notices that it requires the Monad instance, and... yeah, it's there, so that too is fine.

The actual reason we have ap :: Monad m => ... is mostly historical: the Haskell98 Monad class did not have Applicative or even Functor as a superclass, so it was possible to write code Monad m => ... that could then not use fmap or <*>. Therefore the liftM and ap functions were introduced as replacement.

Then, when the better current class hierarchy was established, many instances were simply defined by referring back to the already existing Monad instance, which is after all sufficient for everything.

IMO it is usually a good idea to directly implement <*> and definitely fmap before writing the Monad instance, rather than the other way around.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...