Why can applicative functors have side effects, but functors can't?

后端 未结 4 1365
既然无缘
既然无缘 2020-12-29 07:03

I\'m feeling rather silly asking this question, but it\'s been on my mind for a while and I can\'t find any answers.

So the question is: why can applicative functors

4条回答
  •  被撕碎了的回忆
    2020-12-29 07:40

    Other answers here have rightfully indicated that functors don't allow for side effects because they cannot be combined or sequenced, which is quite true at large, but there is one way to sequence functors: by going inward.

    Let's write a limited Writer functor.

    data Color    = R    | G    | B
    data ColorW a = Re a | Gr a | Bl a deriving (Functor)
    

    and then apply the Free monad type to it

    data Free f a = Pure a | Free (f (Free f a))
    
    liftF :: Functor f => f a -> Free f a
    liftF = Free . fmap Pure
    
    type ColorWriter = Free ColorW
    
    red, blue, green :: a -> ColorWriter a
    red   = liftF . Re
    green = liftF . Gr
    blue  = liftF . Bl
    

    Of course, by the free property, this forms a monad, but the effects are really coming from the "layers" of the functor.

    interpretColors :: ColorWriter a -> ([Color], a)
    interpretColors (Pure a) = ([], a)
    interpretColors (Free (Re next)) = let (colors, a) = interpretColors next
                                       in (R : colors, a)
    ...
    

    So, this is sort of a trick. Really the "computation" is being introduced by the free monad but the material of the computation, the hidden context, is introduced by just a functor. It turns out you can do this with any data type, it need not even be a Functor, but Functor provides a clear way to build it.

提交回复
热议问题