3

我有以下类型:

data S req rsp = Done rsp | Next req (rsp -> S req rsp)

这个想法是将其用作网络通信的纯表示,即:

... Next GetUser $ \uid -> Next (Login uid) $ \success -> Done success

然后将由一些不纯函数评估eval

现在,这是什么(如果有的话?)据我所知,它不是单子,也不是箭头。它似乎是流/管道/自动机/fsm和延续单子之间的东西。这让我觉得这种类型的东西可能有更好的表示,但是什么?

4

2 回答 2

6

这是免费的单子。这个想法是你有一个指令描述,你可以像你的eval函数一样拥有多个解释器。Free Monad 对这个任务的模式进行了抽象。有关详细信息,我推荐这篇很棒的帖子

为了适应您的类型,Free我们可以执行以下操作:

{-# LANGUAGE DeriveFunctor #-}

import Control.Monad.Free

data Instruction req rsp next =
  Respond rsp |
  Interact req (rsp -> next)
  deriving (Functor)

type S req rsp =
  Free (Instruction req rsp)

respond :: rsp -> S req rsp ()
respond rsp =
  liftF (Respond rsp)

interact :: req -> S req rsp rsp
interact req =
  liftF (Interact req id)

现在,感谢Free,S req rsp是一个 monad,这意味着您现在可以使用API组合您的respond和函数。interactMonad

还有更多。和函数可以使用 Template Haskell 和以下额外代码生成respondinteract

{-# LANGUAGE TemplateHaskell #-}

import Control.Monad.Free.TH

makeFree ''Instruction
于 2016-10-23T13:40:47.527 回答
5

您的类型看起来有点像Apfelmus 的operationalmonad Freer也称为monad

data Program inst a where
    Return :: a -> Program inst a
    Bind :: inst a -> (a -> Program inst b) -> Program inst b

instance Monad (Program inst) where
    return = Return
    Return x >>= f = f x
    Bind i next >>= f = Bind i (fmap (>>= f) next)

-- plus the usual Functor and Applicative boilerplate

Program :: (* -> *) -> * -> *表示指令 inst序列,它们使用它们的类型参数来指示在解释器中运行该指令的“返回类型”。构造Bind函数接受一个指令和一个可以在从解释器接收到指令结果后运行的延续。注意如何a存在量化,反映了计算中所有中间步骤的类型与整体类型无关的事实。

与您的类型之间的重要区别在于Program响应的类型由指令确定,而不是在整个计算中固定。这使我们能够对每个请求期望引起的响应做出更细粒度的保证。

例如,这里的状态单子写成Program

data StateI s r where
    Get :: StateI s s
    Put :: s -> StateI s ()

type State s = Program (StateI s)

get :: State s s
get = Bind Get Return
put :: s -> State s ()
put s = Bind (Put s) Return

modify :: (s -> s) -> State s ()
modify f = do
    x <- get
    put (f x)

runState :: State s a -> s -> (s, a)
runState (Return x) s = (s, x)
runState (Bind Get next) s = runState (next s) s
runState (Bind (Put s) next) _ = runState (next ()) s

共同米田引理告诉我们 与Program同构Free。直观地说,它是一个基于->'Functor实例的免费 monad。对于某些操作,如左关联绑定,Program可能比 更有效Free,因为它>>=基于函数组合,而不是可能昂贵地fmapping 任意Functor.

于 2016-10-23T14:04:18.853 回答