使用Haskell导管合并源
是否有可能在管道中构建一个功能(比如zipC2),从而将以下来源转换为:使用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)(我已经设法创建了您
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