Combining Free types

后端 未结 2 1192
猫巷女王i
猫巷女王i 2020-12-08 16:02

I\'ve been recently teaching myself about the Free monad from the free package, but I\'ve come across a problem with it. I would like to have different free mo

2条回答
  •  伪装坚强ぢ
    2020-12-08 16:41

    This is an answer based off of the paper Data types à la carte, except without type classes. I recommend reading that paper.

    The trick is that instead of writing interpreters for Bells and Whistles, you define interpreters for their single functor steps, BellsF and WhistlesF, like this:

    playBellsF :: BellsF (IO a) -> IO a
    playBellsF (Ring  io) = putStrLn "RingRing!"  >> io
    playBellsF (Chime io) = putStr   "Ding-dong!" >> io
    
    playWhistlesF :: WhistelsF (IO a) -> IO a
    playWhistlesF (PeaWhistle   io) = putStrLn "Preeeet!"   >> io
    playWhistlesF (SteamWhistle io) = putStrLn "choo-choo!" >> io
    

    If you choose not to combine them, you can just pass them to Control.Monad.Free.iterM to get back your original play functions:

    playBells    :: Bells a    -> IO a
    playBells    = iterM playBell
    
    playWhistles :: Whistles a -> IO a
    playWhistles = iterM playWhistlesF
    

    ... however because they deal with single steps they can be combined more easily. You can define a new combined free monad like this:

    data BellsAndWhistlesF a = L (BellsF a) | R (WhistlesF a)
    

    Then turn that into a free monad:

    type BellsAndWhistles = Free BellsAndWhistlesF
    

    Then you write an interpreter for a single step of BellsAndWhistlesF in terms of the two sub-interpreters:

    playBellsAndWhistlesF :: BellsAndWhistlesF (IO a) -> IO a
    playBellsAndWhistlesF (L bs) = playBellsF    bs
    playBellsAndWhistlesF (R ws) = playWhistlesF ws
    

    ... and then you get the interpreter for the free monad by just passing that to iterM:

    playBellsAndWhistles :: BellsAndWhistles a -> IO a
    playBellsAndWhistles = iterM playBellsAndWhistlesF
    

    So the answer to your question is that the trick to combining free monads is to preserve more information by defining intermediate interpreters for individual functor steps ("algebras"). These "algebras" are much more amenable to combination than interpreters for free monads.

提交回复
热议问题