What are practical uses of applicative style?

后端 未结 11 690
误落风尘
误落风尘 2021-01-30 01:32

I am a Scala programmer, learning Haskell now. It\'s easy to find practical use cases and real world examples for OO concepts, such as decorators, strategy pattern etc. Books an

11条回答
  •  野趣味
    野趣味 (楼主)
    2021-01-30 02:05

    Since many applicatives are also monads, I feel there's really two sides to this question.

    Why would I want to use the applicative interface instead of the monadic one when both are available?

    This is mostly a matter of style. Although monads have the syntactic sugar of do-notation, using applicative style frequently leads to more compact code.

    In this example, we have a type Foo and we want to construct random values of this type. Using the monad instance for IO, we might write

    data Foo = Foo Int Double
    
    randomFoo = do
        x <- randomIO
        y <- randomIO
        return $ Foo x y
    

    The applicative variant is quite a bit shorter.

    randomFoo = Foo <$> randomIO <*> randomIO
    

    Of course, we could use liftM2 to get similar brevity, however the applicative style is neater than having to rely on arity-specific lifting functions.

    In practice, I mostly find myself using applicatives much in the same way like I use point-free style: To avoid naming intermediate values when an operation is more clearly expressed as a composition of other operations.

    Why would I want to use an applicative that is not a monad?

    Since applicatives are more restricted than monads, this means that you can extract more useful static information about them.

    An example of this is applicative parsers. Whereas monadic parsers support sequential composition using (>>=) :: Monad m => m a -> (a -> m b) -> m b, applicative parsers only use (<*>) :: Applicative f => f (a -> b) -> f a -> f b. The types make the difference obvious: In monadic parsers the grammar can change depending on the input, whereas in an applicative parser the grammar is fixed.

    By limiting the interface in this way, we can for example determine whether a parser will accept the empty string without running it. We can also determine the first and follow sets, which can be used for optimization, or, as I've been playing with recently, constructing parsers that support better error recovery.

提交回复
热议问题