2015-12-15 24 views
8

無料のモナドを他のモナドに変換できますが、タイプがFree f xの場合、生成されたASTのすべてのノードを別のモナドの他のノードにマップしないでツリー全体を印刷します。フリーモナドの印刷

ガブリエル・ゴンザレスuses値我々は(ファンクタとしてChoice x = Choice x xを使用して)のような多型の機能を持っている場合は呼び出すことは容易である

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 

として抽象化することができ、直接

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" 

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

しかし、それはかなり複雑です簡単な操作のためにated ... f x -> bからFree f x -> bに行く他の方法はありますか?

答えて

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 bに変換し、iterの残りの部分はありません。これを因数分解して、より良いパフォーマンスを得ることができます:

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) 
+0

ああ、それはよかったです!ありがとうございました。今私は 'f 'の代数を' f'の代数に変換することを見なければならないことは明らかです。 – nicolas

+0

私はあなたの 'iter'を好きです。私は最近、その一般的な目的に役立つものを見つけようとしましたが(あるものと確信していると感じていますが)何らかの形で正しいタイプのヒットに失敗しました。 – dfeuer

+1

これを 'iter 'fg = go where ...'に対してベンチマークする価値があります。いくつかの測定は、少なくとも2つの引数が再帰を介して一定のままであるときにこれが良い傾向にあることを示しています。 – dfeuer