我试图理解Free monads在Haskell中是如何工作的,为此我一直在尝试做一个例子。我的代码基于Philip JF的答案here。下面是一个例子:
data Free f a = Pure a | Roll (f (Free f a))
--it needs to be a functor
instance Functor f => Functor (Free f) where
fmap f (Pure a) = Pure (f a)
fmap f (Roll x) = Roll (fmap (fmap f) x)
--this is the same thing as (++) basically
concatFree :: Functor f => Free f (Free f a) -> Free f a
concatFree (Pure x) = x
concatFree (Roll y) = Roll (fmap concatFree y)
data F a = One a | Two a a | Two' a a | Three Int a a a
deriving Show
-- Lift F into the Free monad
type FreeF a = Free F a
tree :: FreeF String
tree = Roll (One (Pure "A"))
example1 :: F (FreeF String)
example1 = One (Roll (One (Pure "A")))
上面的代码是有效的。然后我想做的是提出一个FreeF (f (FreeF a))
,以便将concatFree
函数应用于它。这就是我遇到麻烦的地方。
result :: FreeF (FreeF String)
result = Roll (One (Roll (One (Pure "A"))))
上面的代码不起作用。在我看来,这种结构是正确的。我错过了什么?
更准确地说,当我尝试用ghci运行这个函数时,我得到了错误:
FreeMonads3.hs:25:10: error:
• Couldn't match type ‘[Char]’ with ‘Free F String’
Expected type: FreeF (FreeF String)
Actual type: Free F [Char]
• In the expression: Roll (One (Roll (One (Pure "A"))))
In an equation for ‘result’:
result = Roll (One (Roll (One (Pure "A"))))
|
25 | result = Roll (One (Roll (One (Pure "A"))))
2条答案
按热度按时间gfttwv5a1#
在你的表情中:
Roll
和One
构造函数的所有示例都在第一级FreeF
类型内部操作。正如注解中提到的,需要第二个
Pure
运算符才能进入FreeF (FreeF String)
类型。就像这样:附注1:
通过利用Haskell提供的
.
函数组合操作符和$
低优先级函数调用操作符,可以避免上面的重括号嵌套。就像这样:
或者像这样
请注意,上面的
Roll
构造函数的两个示例具有不同的类型。对于One
和Pure
构造函数也是如此。例如,最左边的Pure
构造函数的类型是:FreeF String -> FreeF (FreeF String)
要有一个合适的自由monad,你需要确保你的
F
类型构造函数有一个Functor
示例。确保这一点的最便宜的方法是:但是,作为初学者,手动编写
fmap
的相关代码作为练习可能是值得的。bkhjykvo2#
您定义的
result
类型实际上是:这是因为
Roll
的类型(专用于FreeF
)是F (FreeF a) -> FreeF a
。要获得所需的类型,请使用
Pure
而不是Roll
。Pure
的类型为a -> FreeF a