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
Haskell 管道3.0:非线性拓扑_Haskell_Haskell Pipes - Fatal编程技术网

Haskell 管道3.0:非线性拓扑

Haskell 管道3.0:非线性拓扑,haskell,haskell-pipes,Haskell,Haskell Pipes,我正在看一看用于流处理的pipes 3.0包。做得很好,也很清楚,只是我不能把我的头放在“压缩和合并”部分 我的目标是组合管道,有点像ArrowChoice允许的那样: 我有一个独一无二的制作人 我想将第一个管道应用于左值,另一个应用于右值 然后我想合并结果,并继续 我在教程中定义了fork: fork () = runIdentityP . hoist (runIdentityP . hoist runIdentityP) $ forever $ do a <

我正在看一看用于流处理的pipes 3.0包。做得很好,也很清楚,只是我不能把我的头放在“压缩和合并”部分

我的目标是组合管道,有点像ArrowChoice允许的那样:

  • 我有一个独一无二的制作人
  • 我想将第一个管道应用于左值,另一个应用于右值
  • 然后我想合并结果,并继续
我在教程中定义了
fork

fork () = 
    runIdentityP . hoist (runIdentityP . hoist runIdentityP) $ forever $ do
        a <- request ()
        lift $ respond a
        lift $ lift $ respond a

oddOrEven x = if odd x then Left x else Right x
producer = fromListS [1..0] >-> mapD oddOrEven
isLeft (Left _) = True
isLeft (Right _) = False
isRight = not . isLeft
filterLeft = filterD isLeft
filterRight = filterD isRight
pipe1 = mapD (\x -> ("seen on left", x))
pipe2 = mapD (\x -> ("seen on right", x))

p1 = producer >-> fork    
fork()=
runIdentityP。起重机(运行标识YP.起重机运行标识YP)$forever$do
a->mapD oddOrEven
isLeft(左)=真
isLeft(右)=False
isRight=不是。孤岛
filterLeft=filterD isLeft
filterRight=filterD isRight
pipe1=mapD(\x->(“见左”,x))
pipe2=mapD(\x->(“见右”,x))
p1=生产商>->fork
问题是我不能正确地输入。本教程似乎只演示如何将内部(提升的)管道链作为一个自包含的会话运行,但我希望能够将其值重新导入管道,而不仅仅是对其应用效果。我当然试着模仿这些类型,但它们很快就会有点毛茸茸的

有人能帮我吗?提前谢谢


(注:这种拓扑的一个例子将是本教程的一个很好的补充,或者更好地作为一个关于如何使用管道模拟
控件.Arrow
的章节)

管道
抽象不支持菱形拓扑或任何形式的
Arrow
类行为。这不是API问题,而是此类场景没有正确或定义良好的行为

为了解释原因,请允许我将您的图表简化为以下图表:

          +----+
          | pL |
+----+ => +----+ => +----+
| p1 |              | p2 |
+----+ => +----+ => +----+
          | pR |
          +----+
假设我们在
p1
管道上,我们
响应
pL
。如果您还记得本教程,代理法则要求每个
respond
阻塞直到上游。这意味着在再次请求之前,
p1
无法重新获得控制权。因此,在这一点上,我们有:

  • p1
    在等待来自
    pL的
    请求时被阻止
但是,假设
pL
还没有
请求
,而是
用它自己的值对
p2
响应
s。现在我们有:

  • p1
    在等待来自
    pL的
    请求时被阻止
  • pL
    在等待来自
    p2的
    请求时被阻止
现在假设
p2
而不是
request
s from
pR
。代理法规定,
p2
pR
再次响应之前无法重新获得控制权。现在我们有:

  • p1
    在等待来自
    pL的
    请求时被阻止
  • pL
    在等待来自
    p2的
    请求时被阻止
  • p2
    被阻止,等待
    响应
    来自
    pR
现在,当
pR
请求
s来自
p1
的值时会发生什么?如果我们查看块列表,
p1
仍然被阻止,等待来自
pL
请求,因此无法接收来自
pR
请求。可以说,即使
pL
pR
共享了相同的
请求
签名,也没有正确的“打结”方法

更一般地说,代理法律确保以下两个不变量:

  • 活动管道的每个“上游”管道将在
    respond
  • acive管道的每个“下游”管道将在
    请求时被阻塞
循环或菱形会破坏这些不变量。这就是为什么本教程非常简短地附带指出循环拓扑没有“意义”

你可以在我刚才给你的例子中看到为什么钻石会打破这个不变量。当
p1
拥有控制权时,它位于
pR
的上游,这意味着
pR
请求中被阻止。然而,当
p2
获得控制时,它位于
pR
的下游,这意味着
pR
respond
上被阻断。这导致了一个矛盾,因为自从控制通过
pL
而不是
pR
到达
p2
以来,
pR
不可能改变

机器 所以有两种方法可以解决你的问题。一种解决方案是将所需的拆分行为内联到单个管道中。您可以定义一个
pE
管道,该管道将
pL
pR
的行为组合到一个管道中

这个问题的更优雅的解决方案是爱德华的
机器的风格。您定义了一个比支持
arrowthoice
的代理功能更为有限的抽象,您在该抽象的域中执行arrow-ish操作,然后在完成后将其升级为代理

如果您眯着眼睛看,您可以假装Haskell中存在一类当前可用的协同程序抽象,这是一种偏序。协同程序抽象是对象,从协同程序抽象
C1
到协同程序抽象
C2
的箭头表示可以将
C1
类型的协同程序嵌入
C2
类型的协同程序中(即
C1
C2
的不适当子集)

按照这种偏序,代理可能是终端对象,这意味着您可以将代理视为协同程序的汇编语言。与汇编语言类似,代理提供的保证较少,但您可以在代理中嵌入限制性更强的协程抽象(即更高级的语言)。这些高级语言提供
          +----+
          | pL |
+----+ => +----+ => +----+
| p1 |              | p2 |
+----+ => +----+ => +----+
          | pR |
          +----+
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }

instance Category (Kleisli m) where
    id = Kleisli return
    (Kleisli f) . (Kleisli g) = Kleisli (f <=< g)
kleisliToProxy :: (Proxy p) => Kleisli m a b -> () -> Pipe p a b m r
kleisliToProxy (Kleisli f) = mapMD f
kleisliToProxy id = idT

kleisliToProxy (f . g) = kleisliToProxy f <-< kleisliToProxy g