haskell - 在 Haskell 中,我如何将一个 Free monad 嵌入到另一个 Free monad 中?

标签 haskell monads free-monad

我有两个免费的单子(monad),用于不同上下文中的不同操作。但是,如果特定操作位于上下文中,则一个(主要)DSL 需要包含另一个(action)DSL:

import Control.Monad.Free

data ActionFunctor next = Wait Timeout next
                        | Read URI next

instance Functor ActionFunctor where
  fmap f (Wait timeout next)  = Wait timeout (f next)
  fmap f (Read uri next)      = Read uri (f next)

type Action = Free ActionFunctor


data MajorFunctor next = Log LogText next
                       | Act Action next
                       | Send Message

instance Functor MajorFunctor where
  fmap f (Log text next)    = Log text (f next)
  fmap f (Act action next)  = Act action (f next)
  fmap f (Send message)     = Send message

type Major = Free MajorFunctor

问题是,GHC 会提示 MajorFunctor 认为 Act Action next 中的 Action 是一种 (* -> *),不仅仅是一种类型。这是因为在 data ActionFunctor 定义中,它应该接受 next 作为类型参数,而在 Act Action 行中,它不包含此类参数。但即使这个消息对我来说很清楚,我也不确定是否应该在 Major 仿函数中声明这样的额外类型参数:

data MajorFunctor actionNext next = ...

这看起来很奇怪,因为只有一个数据构造函数会使用该参数,而这样的暴露会将每个 MajorFunctor 变成 MajorFunctor actionNext 并且它看起来完全暴露了太多细节。所以我看了一下 FreeT 变压器,看看它是否是我想要的。但是,就我而言,当 DSL 程序有此类操作时,我只需要调用 Action 解释器,而不是单子(monad)程序中的每个 bind ,所以我也不确定是否变压器是一个很好的解决方案。

最佳答案

一个更简单的解决方案,不需要存在,是将 next 参数嵌入到 Action 中。

data MajorFunctor next = Log LogText next
                       | Act (Action next)
                       | Send Message

instance Functor MajorFunctor where
  fmap f (Log text next) = Log text (f next)
  fmap f (Act action) = Act (fmap f action)
  fmap f (Send message) = Send message

这表示“当您执行 Action 时,它将返回 next”,而 @Cactus 的解决方案表示“当您执行 Action 时> 它将返回一些(未知(存在)类型的),它(只能)变成一个下一个”。

The co-Yoneda lemma说这两个解是同构的。我的版本比较简单,但 Cactus 的版本对于某些操作可能更快,例如在大型 Action 上重复 fmap

关于haskell - 在 Haskell 中,我如何将一个 Free monad 嵌入到另一个 Free monad 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38198048/

相关文章:

list - Data.List.Split 的 `chunksOf` 值为 0

algorithm - Haskell 中的置换算法

Haskell:如何获取#define-d 常量的值?

haskell - 共享由 monad Action 计算的信息

scala - 在 doobie 中为 for-comprehension 编写可选查询?

haskell - 为什么 Stack 选择 ghc 7.10,即使有 ghc8 的 lts?

haskell - 成员函数对于 float 无法正常工作

monads - 使用理由>>

haskell - 何时在 Haskell 中毫无悔意地使用 CPS、共密度与反射

haskell - 如何使用可扩展效果获得 “inflexible semantics of monad transformers”?