- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
是否可以在 Conduit 中构建一个函数(比如 zipC2)来转换以下源:
series1 = yieldMany [2, 4, 6, 8, 16 :: Int]
series2 = yieldMany [1, 5, 6 :: Int]
将生成以下对(此处显示为列表):
[(Nothing, Just 1), (Just 2, Just 1), (Just 4, Just 1), (Just 4, Just 5), (Just 6, Just 6), (Just 8, Just 6), (Just 16, Just 6)]
它将通过以下方式调用比较函数:
runConduitPure ( zipC2 (<=) series1 series1 .| sinkList )
在以前的版本中曾经有一个mergeSources
函数做一些比较相似的事情(虽然没有内存效应),但它在最近的版本(1.3.1)中消失了。
关于函数如何工作的说明:这个想法是采用 2 个来源 A(生成值 a)和 B(生成值 b)。
然后我们生成对:
如果 a < b 我们首先构建 (Just a, Nothing)
如果 b < a 它将产生 (Nothing, Just b)
如果 a == b 我们更新双方并生成 (Just a, Just b)
源中未更新的值不会被消耗,并用于下一轮比较。仅使用更新的值。
然后我们根据 A 和 B 的相对值不断更新这对。
换句话说:如果 a < b,我们更新对的左侧,如果 b < a,则更新右侧,如果 a,则更新两侧== b。任何未使用的值都保留在内存中以供下一轮比较。
最佳答案
下面的代码按预期工作(我调用函数 mergeSort):
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
我从https://github.com/luispedro/conduit-algorithms借用了mergeC2函数...
我只是 Haskell 的初学者,所以代码肯定不是最优的。
关于haskell - 使用 Haskell Conduit 合并资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54644170/
我正在努力通过 xml-conduit 将响应从 http-conduit 转换为 XML 文档。 doPost函数接受一个 XML 文档并将其发布到服务器。服务器使用 XML 文档进行响应。 doP
我有一个函数f :: ByteString -> String ,并且需要一个 Sink ByteString (ResourceT IO) . 我怎么得到这个? 不幸的是,这些文档不是很有帮助...
{-# LANGUAGE DeriveDataTypeable, OverloadedStrings, ScopedTypeVariables #-} module Db ( couchTes
我正在尝试使用 HTTPS 从网站抓取数据。我成功地使用 Network.HTTP.Conduit 发出基本请求(发布凭据等),但未能从响应 header 中提取 cookie 信息(Set-Cook
如何使用 conduit 的库保存文件?我查看了 conduit 的教程,但似乎找不到任何东西,这是我的用例: main :: IO () main = do xxs (readFile fi
使用管道,给定: Prelude> :t (yieldMany [1..10] .| mapC show .| mapC print .| sinkList) (yieldMany [1..10] .
我试图了解如何捕获管道内引发的错误。我相信通过在管道上应用 catchC,我可以生成一个新的管道,该管道将在发生故障时重新运行。 在下面的示例中,我们有一个源,根据 bool 值,该源将抛出自定义虚拟
是否可以在 Conduit 中构建一个函数(比如 zipC2)来转换以下源: series1 = yieldMany [2, 4, 6, 8, 16 :: Int] series2 = yieldMa
我正在尝试写一个 Conduit使用 attoparsec解析器。具体来说,给定 parseOne :: Parser T , 我想构建一个 Conduit ByteString m T重复地将解析器
我有一个 conduit管道处理长文件。我想每 1000 条记录为用户打印一份进度报告,所以我写了这个: -- | Every n records, perform the IO action. --
我想计算http post body的哈希值并在接收时同时解析它,所以我需要这样的函数: unionSinks :: Monad m => Consumer a m r1 -> Consumer a
我使用 XML-conduit 构建了一个 GPX 解析器并且在识别元素和跳过不需要的标签时遇到了过于冗长和脆弱的代码问题。 识别元素(一个小麻烦) 我通过仅比较 nameLocalName 来明确忽
我想使用 xml-conduit , 具体来说 Text.XML.Stream.Parse为了从大型 XML 文件中延迟提取对象列表。 作为测试用例,我使用 the recently re-relea
我正在解析来自 http://hackage.haskell.org/package/xml-conduit-1.1.0.9/docs/Text-XML-Stream-Parse.html 的修改后的
我在使用管道库逐行拆分文本时遇到了一些麻烦。 不幸的是,我正在使用的源数据与行尾极其不一致,其中包含 \r\n和 \n序列在同一个文件中。 我找到了 lines函数在 Data.Conduit.Bin
在 Haskell 中,我正在通过管道处理一些数据。在该处理过程中,我想有条件地将数据存储在 S3 中。是否有任何 S3 库可以让我执行此操作?实际上,我想要做的是“tee”由管道创建的管道,并将其包
与 sourceFile我们得到一个 ByteString 流。 引用我的另一个问题"Combining multiple Sources/Producers into one" , 我能够使用 Zi
我想学习这个概念,以便能够理解和使用 machines 等库。 . 我试着关注 Rúnar Bjarnason's talk on machines ,但是资料太少,基本上就是一堆数据类型。我什至无法
我承认,鉴于我有限的 Haskell 知识,我并不是很了解 Conduits。如果有人可以指导我如何完成这项任务,我将不胜感激:我想获取 rawQuery 操作的输出并将其存储在一个变量中,然后我可以
我有一个简单的应用程序,它发送 HTTP(s) 请求并打印返回的数据: import Network.HTTP.Conduit (simpleHttp) simpleHttp "http://exam
我是一名优秀的程序员,十分优秀!