8

フリーモナドを他のモナドに変換することはできますが、 type の値が与えられた場合、Free f x生成された AST のすべてのノードを別のモナドの他のノードにマップするのではなく、ツリー全体を出力したいと考えています。

Gabriel Gonzales値を直接使用します

showProgram :: (Show a, Show r) => Free (Toy a) r -> String
showProgram (Free (Output a x)) =
    "output " ++ show a ++ "\n" ++ showProgram x
showProgram (Free (Bell x)) =
    "bell\n" ++ showProgram x
showProgram (Free Done) =
    "done\n"
showProgram (Pure r) =
    "return " ++ show r ++ "\n"

これは次のように抽象化できます

showF :: (x -> b) -> ((Free f x -> b) -> f (Free f x) -> b) ->  Free f x -> b
showF backLiftValue backLiftF  = fix (showFU backLiftValue backLiftF)
    where
      showFU :: (x -> b) -> ((Free f x -> b) -> f (Free f x) -> b) -> (Free f x -> b) -> Free f x -> b
      showFU backLiftValue backLiftF next = go . runIdentity . runFreeT where
          go (FreeF c ) = backLiftF next  c
          go (Pure x) =   backLiftValue x 

Choice x = Choice x x(ファンクターとして使用する)のような多相関数がある場合、これは簡単に呼び出すことができます

showChoice :: forall x. (x -> String) ->  Choice x -> String
showChoice show (Choice a b) =  "Choice (" ++ show  a ++  "," ++ show b ++ ")"

しかし、それは単純な操作にはかなり複雑に思えます... から に移行するには、他にどのようなアプローチがありますf x -> bFree f x -> b ?

4

1 に答える 1

9

とを使用iterfmapます。

{-# LANGUAGE DeriveFunctor #-}

import Control.Monad.Free

data Choice x = Choice x x deriving (Functor)

-- iter :: Functor f => (f a -> a) -> Free f a -> a
-- iter _   (Pure a) = a
-- iter phi (Free m) = phi (iter phi <$> m)

showFreeChoice :: Show a => Free Choice a -> String
showFreeChoice =
      iter (\(Choice l r) -> "(Choice " ++ l ++ " " ++ r ++ ")")
    . fmap (\a -> "(Pure " ++ show a ++ ")")

fmapFree f aからに変換しFree f biter残りを行います。これを除外すると、パフォーマンスが少し向上する可能性があります。

iter' :: Functor f => (f b -> b) -> (a -> b) -> Free f a -> b
iter' f g = go where
  go (Pure a)  = g a
  go (Free fa) = f (go <$> fa)
于 2015-12-15T11:05:34.293 に答える