haskell 为什么这个免费的单子例子失败了?

whlutmcx  于 2023-10-19  发布在  其他
关注(0)|答案(2)|浏览(151)

我试图理解Free monads在Haskell中是如何工作的,为此我一直在尝试做一个例子。我的代码基于Philip JF的答案here。下面是一个例子:

  1. data Free f a = Pure a | Roll (f (Free f a))
  2. --it needs to be a functor
  3. instance Functor f => Functor (Free f) where
  4. fmap f (Pure a) = Pure (f a)
  5. fmap f (Roll x) = Roll (fmap (fmap f) x)
  6. --this is the same thing as (++) basically
  7. concatFree :: Functor f => Free f (Free f a) -> Free f a
  8. concatFree (Pure x) = x
  9. concatFree (Roll y) = Roll (fmap concatFree y)
  10. data F a = One a | Two a a | Two' a a | Three Int a a a
  11. deriving Show
  12. -- Lift F into the Free monad
  13. type FreeF a = Free F a
  14. tree :: FreeF String
  15. tree = Roll (One (Pure "A"))
  16. example1 :: F (FreeF String)
  17. example1 = One (Roll (One (Pure "A")))

上面的代码是有效的。然后我想做的是提出一个FreeF (f (FreeF a)),以便将concatFree函数应用于它。这就是我遇到麻烦的地方。

  1. result :: FreeF (FreeF String)
  2. result = Roll (One (Roll (One (Pure "A"))))

上面的代码不起作用。在我看来,这种结构是正确的。我错过了什么?
更准确地说,当我尝试用ghci运行这个函数时,我得到了错误:

  1. FreeMonads3.hs:25:10: error:
  2. Couldn't match type ‘[Char]’ with ‘Free F String’
  3. Expected type: FreeF (FreeF String)
  4. Actual type: Free F [Char]
  5. • In the expression: Roll (One (Roll (One (Pure "A"))))
  6. In an equation for ‘result’:
  7. result = Roll (One (Roll (One (Pure "A"))))
  8. |
  9. 25 | result = Roll (One (Roll (One (Pure "A"))))
gfttwv5a

gfttwv5a1#

在你的表情中:

  1. result :: FreeF (FreeF String)
  2. result = Roll (One (Roll (One (Pure "A"))))

RollOne构造函数的所有示例都在第一级FreeF类型内部操作。
正如注解中提到的,需要第二个Pure运算符才能进入FreeF (FreeF String)类型。就像这样:

  1. result :: FreeF (FreeF String)
  2. result = Roll (One ( Pure (Roll (One (Pure "A")))))

附注1

通过利用Haskell提供的.函数组合操作符和$低优先级函数调用操作符,可以避免上面的重括号嵌套。
就像这样:

  1. result1 :: FreeF (FreeF String)
  2. result1 = Roll $ One $ Pure $ Roll $ One $ Pure "A"

或者像这样

  1. result2 :: FreeF (FreeF String)
  2. result2 = Roll . One . Pure . Roll . One . Pure $ "A"

请注意,上面的Roll构造函数的两个示例具有不同的类型。对于OnePure构造函数也是如此。例如,最左边的Pure构造函数的类型是:
FreeF String -> FreeF (FreeF String)

要有一个合适的自由monad,你需要确保你的F类型构造函数有一个Functor示例。确保这一点的最便宜的方法是:

  1. {-# LANGUAGE DeriveFunctor #-}
  2. data F a = One a | Two a a | Two' a a | Three Int a a a
  3. deriving (Show, Functor)

但是,作为初学者,手动编写fmap的相关代码作为练习可能是值得的。

展开查看全部
bkhjykvo

bkhjykvo2#

您定义的result类型实际上是:

  1. result :: FreeF String
  2. result = Roll (One (Roll (One (Pure "A"))))

这是因为Roll的类型(专用于FreeF)是F (FreeF a) -> FreeF a
要获得所需的类型,请使用Pure而不是RollPure的类型为a -> FreeF a

  1. result :: FreeF (FreeF String)
  2. result = Pure (One (Roll (One (Pure "A"))))

相关问题