可以将自由单子翻译成任何其他单子,但是在给定类型为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 -> b
转换为 Free f x -> b
?
f
翻译成代数Free f
。 - nicolasiter
。最近我试图找到一些类似的通用工具(有信心肯定有这样的工具),但不知何故没有找到合适的类型。 - dfeueriter' f g = go where ...
进行基准测试比较。一些以前的测量结果表明,当至少有两个参数在递归过程中保持不变时,这种方法往往是有效的。 - dfeuerFunctor f => forall b. (f b -> b) -> (a -> b) -> b
等同于Free f a
,并且是 Church free monad 的定义,而toF
与iter'
是相同的。 - András Kovács