1

Free モナドを使用して作成した DSL で Reader を使用したいと考えています。

ここに無料の MonadReader のインスタンスがあることに気付きました。

https://hackage.haskell.org/package/free-4.12.1/docs/src/Control-Monad-Free.html#line-264

EDSL で記述したプログラム内で呼び出そうとするとask、「No such instance MonadReader Free MyDSL」というタイプ エラーが発生します。

最終的には MonadError や Logging モナドなどの DSL で他のモナドを使いたいと思うでしょうが、Reader モナドは私が試した最初のものです。

4

1 に答える 1

3

上でリンクしたように、次のMonadReaderインスタンスがありFreeます。

instance (Functor m, MonadReader e m) => MonadReader e (Free m) where

これが言っているmのは、Functorが であり、 のMonadReader eインスタンスがある場合、 の内部でインスタンスmを利用することもできるということです。ただし、これには、DSL Functor の場合のインスタンスが既に存在している必要があります。これは通常、DSL ファンクターで使用できる選択肢が大幅に制限されるため、通常は望ましくありませMonadReaderFreeMonadReaderm

したがって、使用Free (ReaderT r DSL) aする代わりに、逆にレイヤー化することをお勧めします。つまり 、ファンクターである必要があるReaderT r (Free DSL) aという利点があります。DSLこれをより具体的にするために、DSL がどのように見えるかを述べていないことを踏まえて、TeletypeDSL の例を使用しましょう。

data TeletypeF a = GetChar (Char -> a) | PutChar Char a deriving Functor

type Teletype a = Free TeletypeF a

getChar :: Teletype Char
getChar = liftF (GetChar id)

putChar :: Char -> Teletype ()
putChar c = liftF (PutChar c ())

putStrLn :: String -> Teletype ()
putStrLn str = traverse putChar str >> putChar '\n'

runTeletype :: Teletype a -> IO a
runTeletype = foldFree go
  where go (GetChar k) = k <$> IO.getChar
        go (PutChar c k) = IO.putChar c >> return k

putStrLnDSLプリミティブから派生したプログラムPutCharです。IOモナドを使ってプログラムを解釈することができます。ここで、ReaderTモナド変換子を使用して、行末セパレータの選択を延期できるようにしputStrLnます。したがって、次のように進めます。

type TeletypeReader a = ReaderT Char (Free TeletypeF) a

getChar' :: TeletypeReader Char
getChar' = lift getChar

putChar' :: Char -> TeletypeReader ()
putChar' c = lift (putChar c)

putStrLn' :: String -> TeletypeReader ()
putStrLn' str = do
  traverse_ putChar' str
  sep <- ask
  putChar' sep

runTeletypeReader :: Char -> TeletypeReader a -> IO a
runTeletypeReader sep = runTeletype . flip runReaderT sep

そして今、私たちはできる:

λ> runTeletypeReader '\n' (putStrLn' "Hello" >> putStrLn' "World")
Hello
World

λ> runTeletypeReader ':' (putStrLn' "Hello" >> putStrLn' "World")
Hello:World:
于 2015-09-17T08:31:44.497 に答える