4

我有两个 Free monads 用于不同上下文中的不同操作。但是,如果特定操作在上下文中,则一个 ( major) DSL 需要包含另一个 ( ):action

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 会抱怨inMajorFunctor是一种,而不仅仅是一种类型。这是因为在定义中它应该接受 a作为类型参数,而在该行中它不包含这样的参数。但是即使消息对我来说很清楚,我也不确定是否应该在仿函数中声明这样的额外类型参数:ActionAct Action next(* -> *)data ActionFunctornextAct ActionMajor

data MajorFunctor actionNext next = ...

这看起来很奇怪,因为只有一个数据构造函数会使用该参数,而这样的暴露会变成每一个MajorFunctorMajorFunctor actionNext看起来完全暴露了太多细节。所以我看了一下FreeTtransformer,看看它是否是我想要的。但是,在我的情况下,我只需要Action在 DSL 程序有这样的操作时调用解释器,而不是bind单子程序中的每一个,所以我也不确定转换器是否是一个好的解决方案。

4

2 回答 2

7

一个不需要存在的更简单的解决方案是将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它会返回一些(未知(存在)类型),它可以(仅)变成一个next”。

共同米田引理说这两个解是同构的。fmap我的版本更简单,但对于某些操作,例如在大s 上重复 s,Cactus 可能更快Action

于 2016-07-05T11:32:10.747 回答
5

在您的Act构造函数中,您可以嵌入一个Action a,然后next根据a. 您可以通过使用存在主义将两者联系在一起来做到这一点:

{-# LANGUAGE ExistentialQuantification #-}
data MajorFunctor next = Log LogText next
                       | forall a. Act (Action a) (a -> next)
                       | Send Message

instance Functor MajorFunctor where
  fmap f (Log text next)    = Log text (f next)
  fmap f (Act action next)  = Act action (fmap f next)
  fmap f (Send message)     = Send message
于 2016-07-05T08:55:49.473 回答