Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Events 事件处理程序堆栈_Events_Haskell - Fatal编程技术网

Events 事件处理程序堆栈

Events 事件处理程序堆栈,events,haskell,Events,Haskell,我想实现一个可以在事件中交换的对象堆栈。在接收到上面或下面的事件形式时,对象可以向以太端发出其他事件或更改状态(但保持其在堆栈中的位置) 目前我有这个工作。我有一个类型Animation a b,它是一个事件处理程序的容器,用于接收(从上面)类型a的事件并发出(向上)类型b的事件,我有一个函数handle::handler->Animation g h->Animation e f来堆叠它们 处理程序的实际类型为 Animation g h -> (Either e h) ->

我想实现一个可以在事件中交换的对象堆栈。在接收到上面或下面的事件形式时,对象可以向以太端发出其他事件或更改状态(但保持其在堆栈中的位置)

目前我有这个工作。我有一个类型
Animation a b
,它是一个事件处理程序的容器,用于接收(从上面)类型
a
的事件并发出(向上)类型
b
的事件,我有一个函数
handle::handler->Animation g h->Animation e f
来堆叠它们

处理程序的实际类型为

Animation g h -> (Either e h) -> 
    WriterT [Either g f] IO (Either (Animation e f) (Animation g h))
在这里,
(e h)
是来自上面或下面的事件,
[g f]
是向下或向上发出的事件,
或者(Animation e f)(Animation g h)
是作为独立对象或使用相同处理程序的对象的结果。我不高兴


有没有更优雅的方法可以做到这一点?

这正是来自
管道的
代理
类型所做的。从图表上看,它有点像这样:

 Upstream | Downstream
     +---------+
     |         |
 a' <==       <== b'
     |         |
 a  ==>       ==> b
     |    |    |
     +----|----+
          v
          r
middle :: Int -> Proxy String Int Double Char IO ()
middle int = do
    lift (print int)
    double <- respond (head (show int))
    case double of
        0.0 -> foo
        _   -> bar
换句话说,
request
向上游发送类型为
a'
的值,并等待类型为
a
的响应

请求
的双重功能是
响应
,它在下游接口上进行通信:

respond :: Monad m => b -> Proxy a' a b' b m b'
respond
向下游发送
b
类型的值,并等待
b'
类型的响应

代理可以处于三种状态之一。它可以是:

  • 等待上游的响应
它的类型表示它正在等待
a

waitingUp :: a -> Proxy a' a b' b m r
  • 正在等待下游的响应:
它的类型将指示它正在等待一个
b'

waitingDn :: b' -> Proxy a' a b' b m r
  • 当前处于活动状态,不等待任何操作:
其类型将指示它没有等待任何值:

notWaiting :: Proxy a' a b' b m r
有四种方法可以连接这三种状态:

  • 将下游等待的
    代理连接到活动的
    代理
    ,该代理将生成新的活动
    代理
这就是
(++>)
操作符所做的:

(+>>)
    :: Monad m
    => (b' -> Proxy a' a b' b m r)  -- Waiting on downstream
    ->        Proxy b' b c' c m r   -- Active
    ->        Proxy a' a c' c m r   -- Active
(>>~)
    :: Monad m
    =>       Proxy a' a b' b m r   -- Active
    -> (b -> Proxy b' b c' c m r)  -- Waiting on upstream
    ->       Proxy a' a c' c m r   -- Active
(>~>)
    :: Monad m
    => (a -> Proxy a' a b' b m r)  -- Waiting on upstream
    -> (b -> Proxy b' b c' c m r)  -- Waiting on upstream
    -> (a -> Proxy a' a c' c m r)  -- Waiting on upstream
(>+>)
    :: Monad m
    => (b' -> Proxy a' a b' b m r)  -- Waiting on downstream
    -> (c' -> Proxy b' b c' c m r)  -- Waiting on downstream
    -> (c' -> Proxy a' a c' c m r)  -- Waiting on downstream
  • 将活动的
    代理
    连接到等待上游的
    代理
    ,这将生成新的活动
    代理
这就是
(>>~)
操作员所做的:

(+>>)
    :: Monad m
    => (b' -> Proxy a' a b' b m r)  -- Waiting on downstream
    ->        Proxy b' b c' c m r   -- Active
    ->        Proxy a' a c' c m r   -- Active
(>>~)
    :: Monad m
    =>       Proxy a' a b' b m r   -- Active
    -> (b -> Proxy b' b c' c m r)  -- Waiting on upstream
    ->       Proxy a' a c' c m r   -- Active
(>~>)
    :: Monad m
    => (a -> Proxy a' a b' b m r)  -- Waiting on upstream
    -> (b -> Proxy b' b c' c m r)  -- Waiting on upstream
    -> (a -> Proxy a' a c' c m r)  -- Waiting on upstream
(>+>)
    :: Monad m
    => (b' -> Proxy a' a b' b m r)  -- Waiting on downstream
    -> (c' -> Proxy b' b c' c m r)  -- Waiting on downstream
    -> (c' -> Proxy a' a c' c m r)  -- Waiting on downstream
  • 连接两个都在上游等待的
    代理
    s,以生成一个新的
    代理
    在上游等待
这就是
(>~>)
操作员所做的:

(+>>)
    :: Monad m
    => (b' -> Proxy a' a b' b m r)  -- Waiting on downstream
    ->        Proxy b' b c' c m r   -- Active
    ->        Proxy a' a c' c m r   -- Active
(>>~)
    :: Monad m
    =>       Proxy a' a b' b m r   -- Active
    -> (b -> Proxy b' b c' c m r)  -- Waiting on upstream
    ->       Proxy a' a c' c m r   -- Active
(>~>)
    :: Monad m
    => (a -> Proxy a' a b' b m r)  -- Waiting on upstream
    -> (b -> Proxy b' b c' c m r)  -- Waiting on upstream
    -> (a -> Proxy a' a c' c m r)  -- Waiting on upstream
(>+>)
    :: Monad m
    => (b' -> Proxy a' a b' b m r)  -- Waiting on downstream
    -> (c' -> Proxy b' b c' c m r)  -- Waiting on downstream
    -> (c' -> Proxy a' a c' c m r)  -- Waiting on downstream
  • 连接两个都在下游等待的
    代理
    s,以生成一个新的
    代理
    在下游等待
这就是
(>++>)
操作符所做的:

(+>>)
    :: Monad m
    => (b' -> Proxy a' a b' b m r)  -- Waiting on downstream
    ->        Proxy b' b c' c m r   -- Active
    ->        Proxy a' a c' c m r   -- Active
(>>~)
    :: Monad m
    =>       Proxy a' a b' b m r   -- Active
    -> (b -> Proxy b' b c' c m r)  -- Waiting on upstream
    ->       Proxy a' a c' c m r   -- Active
(>~>)
    :: Monad m
    => (a -> Proxy a' a b' b m r)  -- Waiting on upstream
    -> (b -> Proxy b' b c' c m r)  -- Waiting on upstream
    -> (a -> Proxy a' a c' c m r)  -- Waiting on upstream
(>+>)
    :: Monad m
    => (b' -> Proxy a' a b' b m r)  -- Waiting on downstream
    -> (c' -> Proxy b' b c' c m r)  -- Waiting on downstream
    -> (c' -> Proxy a' a c' c m r)  -- Waiting on downstream
下面是以这种方式实现和连接的三个堆栈帧的示例。我将使用堆栈从上游开始的约定,尽管实现是完全对称的,如果您愿意,可以使用相反的约定:

import Pipes.Core
import Pipes

--                +-+-- Closed upstream interface
--                | |
--                v v
up :: () -> Proxy X () String Int IO ()
up () = do
    str1 <- respond 4
    lift (putStrLn str1)
    str2 <- respond 5
    lift (putStrLn str2)

middle :: Int -> Proxy String Int Double Char IO ()
middle int = do
    lift (print int)
    double <- respond (head (show int))
    lift (print double)
    int' <- request (show double)
    middle int'

--  Closed downstream interface --+-+
--                                | |
--                                v  v
down :: Char -> Proxy Double Char () X IO ()
down char1 = do
    lift (print char1)
    char2 <- request (1.0)
    lift (print char2)
    char3 <- request (2.0)
    lift (print char3)

--                   +-+--+--+-- Everything closed
--                   | |  |  |
--                   v v  v  v
total :: () -> Proxy X () () X IO ()
total = up >~> middle >~> down

main :: IO ()
main = runEffect $ total ()
尝试手动跟踪执行路径,从
代理开始。每次
向上
用值响应
时,将控制权交给
中间
,每次
中间
响应
时,将控制权交给
向下
的值。反之亦然,每次
down
请求一个值,将控制权交给
middle
,每次
middle
请求一个值,将控制权交给
up
。如果链中的任何管道终止,则整个链终止

编辑:要回答您的问题,可以,您可以根据结果更改行为。只需像这样写
middle

 Upstream | Downstream
     +---------+
     |         |
 a' <==       <== b'
     |         |
 a  ==>       ==> b
     |    |    |
     +----|----+
          v
          r
middle :: Int -> Proxy String Int Double Char IO ()
middle int = do
    lift (print int)
    double <- respond (head (show int))
    case double of
        0.0 -> foo
        _   -> bar

当您对两个
Proxy
s排序时,第二个
Proxy
从第一个
Proxy
结束的地方开始。您不仅限于排序基本命令,如
request
respond
。您可以调用任意数量的
代理
,作为较大的
代理
中的子例程,只要它共享相同的上游和下游接口。

您的
动画
类型听起来类似于
管道
导管
库offer@cdk,我对这些不太熟悉,但似乎两者都依赖于数据转换,而对我来说,最重要的要求是每个
动画
能够替换自身。是否有可能以这样的方式编写
中间
,即每当它从上游得到某个响应时,它就会用另一个
代理
替换自身,相同类型的
foo
,这样整个效果就相当于
up>~>foo>~>down
?它能变成foo吗?换句话说,这个例子对于消息传递非常有用,但是状态呢?是的。我更新了我的答案,详细说明了如何做到这一点。简单的回答是:只要直接呼叫
foo
,它就会正常工作。