LINUX.ORG.RU

conduits: выбор вариантов

 


0

5

Здравствуйте.

Есть такой код:

{-# LANGUAGE OverloadedStrings #-}

import Data.Conduit
import Conduit
import Control.Concurrent.Async
import Data.Conduit.Network
import Data.Conduit.Binary as DCB
import Data.Conduit.List as DCL
import Data.ByteString.Char8 as B

hostnameListen = "127.0.0.1"

main :: IO ()
main = 
  runTCPServer (serverSettings 4003 hostnameListen) $ \server ->
    appSource server $= DCB.lines $= condToInt $= condToBS $$ appSink server

condToInt :: Conduit ByteString IO Int
condToInt = awaitForever $ \bs -> do
  let res = B.readInt bs
  case res of
    Nothing -> yield 0
    Just (x, _) -> yield x

condToBS :: Conduit Int IO ByteString
condToBS = awaitForever $ \i -> do
  let result = B.pack . show $ i
  yield result

condMultiplN :: Int -> Conduit Int IO Int
condMultiplN m = awaitForever $ \i ->
  yield $ i * m

Ломаю голову над следующим: как сделать так, чтобы в

appSource server $= DCB.lines $= condToInt $= condToBS $$ appSink server
после condToInt, в зависимости от чётности числа (к примеру), вышедшего из этого кондуита, зависело то, какой кондуит дальше будет его обрабатывать.

Поясню подробнее.

main :: IO ()
main = 
  runTCPServer (serverSettings 4003 hostnameListen) $ \server -> do
    (resum1, res) <- appSource server $= DCB.lines $$+ condToInt 
    case (odd res) of
      True -> resum1 $$+- condMultiplN 2 =$ condToBS $$ appSink server
      otherwise -> resum1 $$+- condMultiplN 3 =$ condToBS $$ appSink server

Я знаю, что показанный код нерабочий, ибо

($$+) :: Monad m => Source m a -> Sink a m b -> m (ResumableSource m a, b)
но мне кажется, что мою мысль передать получилось: взять что-то, проверить и пустить по одному из направлений, взять следующее что-то, опять проверить и пустить по одному из направлений, повторить.

Вопрос: как этого добиться?


Ответ на: комментарий от anonymous

Да, то, что надо:

{-# LANGUAGE OverloadedStrings #-}

import Data.Conduit
import Conduit
import Data.Conduit.Network
import Data.Conduit.Binary as DCB
import Data.Conduit.List as DCL

import Control.Applicative


import Data.ByteString.Char8 as B

hostnameListen = "127.0.0.1"

main :: IO ()
main = 
  runTCPServer (serverSettings 4003 hostnameListen) $ \server ->
    appSource server $= DCB.lines $= condToInt $= condTransf $$ appSink server

condToInt :: Monad m => Conduit ByteString m Int
condToInt = awaitForever $ \bs -> do
  let res = B.readInt bs
  case res of
    Nothing -> yield 0
    Just (x, _) -> yield x

condToBS :: Monad m => Conduit Int m ByteString
condToBS = awaitForever $ \i -> do
  let result = B.pack . show $ i
  yield result

condMultiplN :: Monad m => Int -> Conduit Int m Int
condMultiplN m = awaitForever $ \i ->
  yield $ i * m

-- объединяем для удобства в один кондуит
condTransf :: Monad m => Conduit Int m ByteString
condTransf = condSplit =$= condConct =$= condToBS

-- разделяем поток на 2 части
condSplit :: Monad m => Conduit Int m (Either Int Int)
condSplit = DCL.map $ \i ->
  if odd i then Left i else Right i

-- сливаем поток из 2-х частей в один поток
condConct :: Monad m => Conduit (Either Int Int) m Int
condConct = getZipConduit $ 
  ZipConduit condEven *>
    ZipConduit condOdd

-- нечётные числа умножить на 3
condOdd :: Monad m => Conduit (Either Int Int) m Int
condOdd = DCL.mapMaybe (either Just (const Nothing)) =$= condMultiplN 3

-- чётные числа умножить на 2
condEven :: Monad m => Conduit (Either Int Int) m Int
condEven = DCL.mapMaybe (either (const Nothing) Just) =$= condMultiplN 2

По идее, если задача будет требовать разделения на большее количество отдельных потоков, то надо будет определить такой тип данных, который будет расширением Either до нужного числа вариантов.

Всем спасибо за помощь!

HolyBoy
() автор топика
Ответ на: комментарий от HolyBoy

Раз местами и так однострочники, то можно вот так:

condToInt :: Monad m => Conduit ByteString m Int
condToInt = awaitForever $ yield . maybe 0 fst . B.readInt

condToBS :: Monad m => Conduit Int m ByteString
condToBS = awaitForever $ yield . B.pack . show

condMultiplN :: Monad m => Int -> Conduit Int m Int
condMultiplN m = awaitForever $ yield . (* m)
quasimoto ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.