How do I implement Reader using free monads?

后端 未结 2 2017
醉梦人生
醉梦人生 2021-02-15 06:05

Ok, so I have figured out how to implement Reader (and ReaderT, not shown) using the operational package:

{-# LANGUAGE GADTs, ScopedTyp         


        
2条回答
  •  北恋
    北恋 (楼主)
    2021-02-15 06:34

    I don't think it can be done except they way you have. But, I don't think this is unique to reader. Consider the free monad version of writer

    data WriterF m a = WriterF m a deriving (Functor)
    
    type Writer m = Free (WriterF m)
    

    obviously, WriterF is isomorphic to writer, but this does behave the way we would expect with the simple algebra

    algebraWriter :: Monoid m => WriterF m (m,a) -> (m,a)
    algebraWriter (WriterF m1 (m2,a)) = (m1 <> m2,a)
    

    thus

    runWriter :: Monoid m => Writer m a -> (m,a)
    runWriter (Pure a) = (mempty,a)
    runWriter (Free x) = algebraWriter . fmap runWriter $ x
    

    Similarly, I think of the Free reader as

    type ReaderF r = (->) r
    
    type Reader r = Free (ReaderF r)
    

    I like this, because adding them gives you the state monad

    type State x = Free ((ReaderF x) :+: (WriterF x))
    
    runState :: State x a -> x -> (a,x)
    runState (Pure a) x                    = (a,x)
    runState (Free (Inl f)) x              = runState (f x) x
    runState (Free (Inr (WriterF x f))) _  = runState f x
    

    Note, that your operational solution could be made to work with Free by using the "free functor", as can anything that works with operational

    data FreeFunctor f x = forall a. FreeFunctor (f a) (a -> x)
    

    but, that FreeFunctor ReaderI is also isomorphic to (->).

提交回复
热议问题