使用Haskell导管合并源

使用Haskell导管合并源,haskell,conduit,Haskell,Conduit,是否有可能在管道中构建一个功能(比如zipC2),从而将以下来源转换为: series1 = yieldMany [2, 4, 6, 8, 16 :: Int] series2 = yieldMany [1, 5, 6 :: Int] 转换为一个将产生以下对(如列表所示): 它将通过比较函数按以下方式调用: runConduitPure ( zipC2 (<=) series1 series1 .| sinkList ) runConduitPure(zipC2)(我已经设法创建了您

是否有可能在管道中构建一个功能(比如zipC2),从而将以下来源转换为:

series1 = yieldMany [2, 4, 6, 8, 16 :: Int]

series2 = yieldMany [1, 5, 6 :: Int]
转换为一个将产生以下对(如列表所示):

它将通过比较函数按以下方式调用:

runConduitPure ( zipC2 (<=) series1 series1 .| sinkList )

runConduitPure(zipC2)(我已经设法创建了您的
zipC2
函数:

import Data.Ord
import Conduit
import Control.Monad

zipC2Def :: (Monad m) => (a -> a -> Bool) -> ConduitT () a m () -> ConduitT () a m () -> (Maybe a, Maybe a) -> ConduitT () (Maybe a, Maybe a) m ()
zipC2Def f c1 c2 (s1, s2) = do
  ma <- c1 .| peekC
  mb <- c2 .| peekC
  case (ma, mb) of
    (Just a, Just b) ->
      case (f a b, f b a) of
        (True, True) -> do
          yield (ma, mb)
          zipC2Def f (c1 .| drop1) (c2 .| drop1) (ma, mb)
        (_, True) -> do
          yield (s1, mb)
          zipC2Def f c1 (c2 .| drop1) (s1, mb)
        (True, _) -> do
          yield (ma, s2)
          zipC2Def f (c1 .| drop1) c2 (ma, s2)
        _ ->
          zipC2Def f (c1 .| drop1) (c2 .| drop1) (ma, s2)
    (Just a, Nothing) -> do
      yield (ma, s2)
      zipC2Def f (c1 .| drop1) c2 (ma, s2)
    (Nothing, Just b) -> do
      yield (s1, mb)
      zipC2Def f c1 (c2 .| drop1) (s1, mb)
    _ -> return ()
  where
    drop1 = dropC 1 >> takeWhileC (const True)

zipC2 :: (Monad m) => (a -> a -> Bool) -> ConduitT () a m () -> ConduitT () a m () -> ConduitT () (Maybe a, Maybe a) m ()
zipC2 f c1 c2 = zipC2Def f c1 c2 (Nothing, Nothing)

main :: IO ()
main = 
  let
    series1 = yieldMany [2, 4, 6, 8, 16 :: Int] :: ConduitT () Int Identity ()
    series2 = yieldMany [1, 5, 6 :: Int] :: ConduitT () Int Identity ()
  in
  putStrLn $ show $ runConduitPure $
    (zipC2 (<=) series1 series2)
    .| sinkList
导入数据.Ord 导入导管 进口管制 zipC2Def::(Monad m)=>(a->a->Bool)->conduit()a m()->conduit()a m()->(可能是a,可能是a)->conduit()(可能是a,可能是a)m() zipC2Def f c1 c2(s1,s2)=do 马多 产量(毫安,毫巴) zipC2Def f(c1.|下降1)(c2.|下降1)(ma,mb) (对)->做什么 产量(s1,mb) zipC2Def f c1(c2.| drop1)(s1,mb) (对)->do 产量(ma,s2) zipC2Def f(c1.|下降1)c2(ma,s2) _ -> zipC2Def f(c1.|下降1)(c2.|下降1)(ma,s2) (只是一个,没什么)->做 产量(ma,s2) zipC2Def f(c1.|下降1)c2(ma,s2) (没什么,只是b)->做 产量(s1,mb) zipC2Def f c1(c2.| drop1)(s1,mb) _->返回() 哪里 drop1=dropc1>>takeWhileC(常数为真) zipC2::(Monad m)=>(a->a->Bool)->conduit()a m()->conduit()a m()->conduit()(可能是a,可能是a)m() zipC2 f c1 c2=zipC2Def f c1 c2(无,无) main::IO() 主要= 让 series1=yieldmanny[2,4,6,8,16::Int]::conduit()Int Identity() series2=yieldmanny[1,5,6::Int]::conduit()Int Identity() 在里面 putStrLn$show$runConduitPure$
(zipC2(下面的代码按预期工作(我调用了函数mergeSort):

module Data.conductor.Merge其中
导入前奏曲(单子、布尔、可能(…)、表演、情商)
导入前奏曲(否则返回)
导入前奏曲($)
导入导管(导管)
导入导管(evalStateC、mapC、yield、wait)
导入导管((.|))
导入控制.Monad.State(获取、放置、提升)
进口控制.Monad.Trans.State.Strict(StateT)
将限定的Data.conductor.Internal作为CI导入
--|获取两个源并合并它们。
--这来自https://github.com/luispedro/conduit-algorithms 感谢路易斯·佩德罗·科埃略。
mergeC2::(Monad m)=>(a->a->Bool)->conduit()a m()->conduit()a m()->conduit()a m()
合并C2比较器(CI.conduit s1)(CI.conduit s2)=CI.conduit$processMergeC2比较器s1 s2
processMergeC2::Monad m=>(a->a->Bool)
->(()->CI.Pipe()()a()m())->CI.Pipe()()a()m()--s1 conduct()a m()
->((()->CI.Pipe()()a()m())->CI.Pipe()()a()m())--s2 conduct()a m()
->((()->CI.Pipe()()a()mb)->CI.Pipe()()a()mb--rest conduct()am()
processMergeC2比较器s1 s2 rest=go(s1 CI.Done)(s2 CI.Done)
哪里
转到s1'@(CI.HaveOutput s1'v1)s2'@(CI.HaveOutput s2'v2)——s1'@和s2'@只需命名模式表达式即可
|比较器v1 v2=CI.HaveOutput(转到s1's2'')v1
|否则=CI.HaveOutput(转到s1''s2')v2
go s1'@CI.Done{}(CI.HaveOutput s v)=CI.HaveOutput(go s1)v
go(CI.HaveOutput s v)s1'@CI.Done{}=CI.HaveOutput(go s s1')v
go CI.Done{}CI.Done{}=rest()
go(CI.PipeM p)left=do
下一个a->Bool->conduit()a m()->conduit()a m()->conduit()(TaggedItem a)m()
mergeTag func系列1系列2=mergeC2(tagSort func)TagEdSeries1 TagEdSeries2
哪里
taggedSeries1=series1.| mapC(\item->TaggedItem LeftItem)
taggedSeries2=series2.| mapC(\item->TaggedItem RightItem)
tagSort::(a->a->Bool)->TaggedItem a->TaggedItem a->Bool
tagSort f(TaggedItem uuItem1)(TaggedItem uItem2)=f item1 item2
输入StateMergePair a=(可能是a,可能是a)
pairTagC::(Monad m)=>conduit(TaggedItem a)(StateMergePair a)(StateT(StateMergePair a)m)()
pairtag=do
输入返回()
只需taggedItem->do
stateMergePair stateMergePair a->stateMergePair a
updateStateMergePair(TaggedItem标记项)(Just leftItem,Just rightItem)=的大小写标记
LeftItem->(Just item,Just rightItem)
RightItem->(仅限leftItem,仅限item)
updateStateMergePair(TaggedItem标记项)(无,仅为rightItem)=的大小写标记
LeftItem->(Just item,Just rightItem)
RightItem->(无,仅项目)
updateStateMergePair(TaggedItem标记项)(仅leftItem,无)=的大小写标记
LeftItem->(仅项目,无)
RightItem->(仅限leftItem,仅限item)
updateStateMergePair(TaggedItem标记项)(Nothing,Nothing)=的大小写标记
LeftItem->(仅项目,无)
RightItem->(无,仅项目)
pairTag::(Monad m)=>conduit(TaggedItem a)(StateMergePair a)m()
pairTag=evalStateC(无,无)pairTag
合并排序::(Monad m)=>(a->a->Bool)->conduit()a m()->conduit()a m()->conduit()(StateMergePair a)m()
mergeSort func series1 series2=合并标签func series1 series2.| pairTag
我从…借用了mergeC2函数


我只是Haskell的初学者,所以代码肯定不是最优的。

是的,我考虑过使用它,但不幸的是,即使它们没有用于更新,它也会消耗元素:例如,我得到:[(没有,只有1),(只有4,没有),(只有6,只有6)],而不是预期的结果[(没有,只有1),(只有2,只有1),(只有4,只有1),(只有4,只有5),(只有6,只有5),(只有6,只有6),(只有8,只有6),(只有16,只有6)]…为了实现这一点,需要有一些记忆效应。元素的消费有任何特定的顺序吗?例如,首先我们从源A消费元素,然后从B消费元素,然后再从A消费元素等等。我们只从元素最低的源消费元素。我们只在以下情况下从两个源消费元素:
import Data.Ord
import Conduit
import Control.Monad

zipC2Def :: (Monad m) => (a -> a -> Bool) -> ConduitT () a m () -> ConduitT () a m () -> (Maybe a, Maybe a) -> ConduitT () (Maybe a, Maybe a) m ()
zipC2Def f c1 c2 (s1, s2) = do
  ma <- c1 .| peekC
  mb <- c2 .| peekC
  case (ma, mb) of
    (Just a, Just b) ->
      case (f a b, f b a) of
        (True, True) -> do
          yield (ma, mb)
          zipC2Def f (c1 .| drop1) (c2 .| drop1) (ma, mb)
        (_, True) -> do
          yield (s1, mb)
          zipC2Def f c1 (c2 .| drop1) (s1, mb)
        (True, _) -> do
          yield (ma, s2)
          zipC2Def f (c1 .| drop1) c2 (ma, s2)
        _ ->
          zipC2Def f (c1 .| drop1) (c2 .| drop1) (ma, s2)
    (Just a, Nothing) -> do
      yield (ma, s2)
      zipC2Def f (c1 .| drop1) c2 (ma, s2)
    (Nothing, Just b) -> do
      yield (s1, mb)
      zipC2Def f c1 (c2 .| drop1) (s1, mb)
    _ -> return ()
  where
    drop1 = dropC 1 >> takeWhileC (const True)

zipC2 :: (Monad m) => (a -> a -> Bool) -> ConduitT () a m () -> ConduitT () a m () -> ConduitT () (Maybe a, Maybe a) m ()
zipC2 f c1 c2 = zipC2Def f c1 c2 (Nothing, Nothing)

main :: IO ()
main = 
  let
    series1 = yieldMany [2, 4, 6, 8, 16 :: Int] :: ConduitT () Int Identity ()
    series2 = yieldMany [1, 5, 6 :: Int] :: ConduitT () Int Identity ()
  in
  putStrLn $ show $ runConduitPure $
    (zipC2 (<=) series1 series2)
    .| sinkList
module Data.Conduit.Merge where

import Prelude (Monad, Bool, Maybe(..), Show, Eq)
import Prelude (otherwise, return)
import Prelude (($))
import Conduit (ConduitT)
import Conduit (evalStateC, mapC, yield, await)
import Conduit ((.|))
import Control.Monad.State (get, put, lift)
import Control.Monad.Trans.State.Strict (StateT)

import qualified Data.Conduit.Internal as CI

-- | Takes two sources and merges them.
-- This comes from https://github.com/luispedro/conduit-algorithms made available thanks to Luis Pedro Coelho.
mergeC2 :: (Monad m) => (a -> a -> Bool) -> ConduitT () a m () -> ConduitT () a m () -> ConduitT () a m ()
mergeC2 comparator (CI.ConduitT s1) (CI.ConduitT s2) = CI.ConduitT $  processMergeC2 comparator s1 s2

processMergeC2 :: Monad m => (a -> a -> Bool)
                        -> ((() -> CI.Pipe () () a () m ()) -> CI.Pipe () () a () m ()) -- s1    ConduitT () a m ()
                        -> ((() -> CI.Pipe () () a () m ()) -> CI.Pipe () () a () m ()) -- s2    ConduitT () a m ()
                        -> ((() -> CI.Pipe () () a () m b ) -> CI.Pipe () () a () m b ) -- rest  ConduitT () a m ()
processMergeC2 comparator s1 s2 rest = go (s1 CI.Done) (s2 CI.Done)
    where
        go s1''@(CI.HaveOutput s1' v1) s2''@(CI.HaveOutput s2' v2)  -- s1''@ and s2''@ simply name the pattern expressions
            | comparator v1 v2 = CI.HaveOutput (go s1' s2'') v1
            | otherwise = CI.HaveOutput (go s1'' s2') v2
        go s1'@CI.Done{} (CI.HaveOutput s v) = CI.HaveOutput (go s1' s) v
        go (CI.HaveOutput s v) s1'@CI.Done{}  = CI.HaveOutput (go s s1')  v
        go CI.Done{} CI.Done{} = rest ()
        go (CI.PipeM p) left = do
            next <- lift p
            go next left
        go right (CI.PipeM p) = do
            next <- lift p
            go right next
        go (CI.NeedInput _ next) left = go (next ()) left
        go right (CI.NeedInput _ next) = go right (next ())
        go (CI.Leftover next ()) left = go next left
        go right (CI.Leftover next ()) = go right next

data MergeTag = LeftItem | RightItem deriving (Show, Eq)
data TaggedItem a = TaggedItem MergeTag a deriving (Show, Eq)
mergeTag :: (Monad m) => (a -> a -> Bool) -> ConduitT () a m () -> ConduitT () a m () -> ConduitT () (TaggedItem a) m ()
mergeTag func series1 series2 = mergeC2 (tagSort func) taggedSeries1 taggedSeries2
                where
                    taggedSeries1 = series1 .| mapC (\item -> TaggedItem LeftItem item)
                    taggedSeries2 = series2 .| mapC (\item -> TaggedItem RightItem item)
                    tagSort :: (a -> a -> Bool) -> TaggedItem a -> TaggedItem a -> Bool
                    tagSort f (TaggedItem _ item1) (TaggedItem _ item2) = f item1 item2

type StateMergePair a = (Maybe a, Maybe a)
pairTagC :: (Monad m) => ConduitT  (TaggedItem a) (StateMergePair a) (StateT (StateMergePair a) m) ()
pairTagC = do
    input <- await
    case input of
        Nothing -> return ()
        Just taggedItem -> do
            stateMergePair <- lift get
            let outputState = updateStateMergePair taggedItem stateMergePair
            lift $ put outputState
            yield outputState
            pairTagC

updateStateMergePair :: TaggedItem a -> StateMergePair a -> StateMergePair a
updateStateMergePair (TaggedItem tag item) (Just leftItem, Just rightItem) = case tag of
    LeftItem -> (Just item, Just rightItem)
    RightItem -> (Just leftItem, Just item)

updateStateMergePair (TaggedItem tag item) (Nothing, Just rightItem) = case tag of
    LeftItem -> (Just item, Just rightItem)
    RightItem -> (Nothing, Just item)

updateStateMergePair (TaggedItem tag item) (Just leftItem, Nothing) = case tag of
    LeftItem -> (Just item, Nothing)
    RightItem -> (Just leftItem, Just item)

updateStateMergePair (TaggedItem tag item) (Nothing, Nothing) = case tag of
    LeftItem -> (Just item, Nothing)
    RightItem -> (Nothing, Just item)

pairTag :: (Monad m) => ConduitT  (TaggedItem a) (StateMergePair a) m ()
pairTag = evalStateC (Nothing, Nothing) pairTagC

mergeSort :: (Monad m) => (a -> a -> Bool) -> ConduitT () a m () -> ConduitT () a m () -> ConduitT () (StateMergePair a) m ()
mergeSort func series1 series2 = mergeTag func series1 series2 .| pairTag