2013-03-15 13 views
7

Ok, vì vậy tôi đã tìm ra cách để thực hiện Reader (và ReaderT, không hiển thị) bằng cách sử dụng operational gói:Làm cách nào để triển khai Reader bằng monads miễn phí?

{-# LANGUAGE GADTs, ScopedTypeVariables #-} 

import Control.Monad.Operational 

data ReaderI r a where 
    Ask :: ReaderI r r 

type Reader r a = Program (ReaderI r) a 

ask :: Reader r r 
ask = singleton Ask 

runReader :: forall r a. Reader r a -> r -> a 
runReader = interpretWithMonad evalI 
    where evalI :: forall b. ReaderI r b -> (r -> b) 
      evalI Ask = id 

Nhưng tôi không thể tìm ra cho cuộc sống của tôi làm thế nào để làm điều này với monads miễn phí (Tôi đang sử dụng gói free của Edward Kmett). Gần nhất tôi đã nhận được là thế này, mà tôi hiểu được gian lận (một cái gì đó về cách ((->) r) đã là một đơn nguyên):

import Control.Monad.Free 

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

ask :: Reader r r 
ask = Free Pure 

runReader :: Reader r a -> r -> a 
runReader (Pure a) _ = a 
runReader (Free k) r = runReader (k r) r 

-- Or, more simply and tellingly: 
-- 
-- > runReader = retract 

Thậm chí nếu điều này không phải như câm như tôi nghi ngờ nó là, nó không phải là những gì tôi muốn vì điều tôi muốn, về cơ bản, là có thể kiểm tra số Reader làm dữ liệu ...

+1

Tôi không nghĩ rằng nó có thể được thực hiện mà không có một loại chức năng ở đâu đó. –

Trả lời

3

Tôi không nghĩ rằng nó có thể được thực hiện ngoại trừ cách bạn có. Nhưng, tôi không nghĩ điều này là duy nhất đối với người đọc. Hãy xem xét các phiên bản đơn nguyên miễn phí của nhà văn

data WriterF m a = WriterF m a deriving (Functor) 

type Writer m = Free (WriterF m) 

rõ ràng, WriterF là đẳng cấu với nhà văn, nhưng điều này không hành xử theo cách chúng ta mong chờ với các đại số đơn giản

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

do đó

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

Tương tự, tôi nghĩ về Trình đọc miễn phí là

type ReaderF r = (->) r 

type Reader r = Free (ReaderF r) 

Tôi thích video này, bởi vì bổ sung chúng mang đến cho bạn những đơn nguyên nhà nước

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 

Lưu ý, rằng giải pháp hoạt động của bạn có thể được thực hiện để làm việc với Free bằng "functor tự do", như thể bất cứ điều gì mà làm việc với hoạt động

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

nhưng, FreeFunctor ReaderI cũng là đẳng cấu để (->).

1

Vâng, tôi đã xem xét điều này trong 3 giờ và tôi nghĩ rằng tôi đã tìm thấy thứ tôi thích hơn. Kể từ khi Reader applicative là giống như Reader đơn nguyên, chúng ta có thể thử một phiên bản applicative của operational:

{-# LANGUAGE RankNTypes, GADTs, FlexibleInstances #-} 

import Control.Applicative 

data ProgramA instr a where 
    Pure :: a -> ProgramA r a 
    Ap :: ProgramA r (a -> b) -> ProgramA r a -> ProgramA r b 
    Instr :: instr a -> ProgramA instr a 

infixl `Ap` 

instance Functor (ProgramA instr) where 
    fmap f (Pure a) = Pure (f a) 
    fmap f (ff `Ap` fa) = ((f .) <$> ff) `Ap` fa 
    fmap f instr = Pure f `Ap` instr 

instance Applicative (ProgramA instr) where 
    pure = Pure 
    (<*>) = Ap 

interpretA :: Applicative f => 
       (forall a. instr a -> f a) 
      -> ProgramA instr a 
      -> f a 
interpretA evalI (Pure a) = pure a 
interpretA evalI (ff `Ap` fa) = interpretA evalI ff <*> interpretA evalI fa 
interpretA evalI (Instr i) = evalI i 

data ReaderI r a where 
    Ask :: ReaderI r r 

type Reader r a = ProgramA (ReaderI r) a 

ask :: Reader r r 
ask = Instr Ask 

runReader :: Reader r a -> r -> a 
runReader = interpretA (\Ask -> id) 

instance Monad (ProgramA (ReaderI r)) where 
    return = pure 
    ma >>= f = runReader <$> fmap f ma <*> ask 

Cấu trúc của một ProgramA (ReaderI r) a) có thể được kiểm tra thẳng thắn hơn hoặc Program (ReaderI r) a hoặc Free ((->) r) a.