LoginSignup
2
1

More than 5 years have passed since last update.

Data.Conduit

Posted at

噂のconduit。今回は標準入力触るスクリプトにしたのでconduit.hsみたいな感じで以下を保存。標準入力への入力を大文字にするだけ。.の入力で終了する。

module Main (main) where
import Data.Char (ord, chr, toUpper)
import Data.Conduit
import qualified Data.Conduit.Binary as B
import qualified Data.Conduit.Util as U
import qualified Data.ByteString as BS
import Data.Word (Word8)
import System.IO (stdin, stdout)

main :: IO ()
main = runResourceT $ do
  B.sourceHandle stdin
    $= B.takeWhile (\c -> c /= word8 '.')
    $= filterUc
    $$ B.sinkHandle stdout
  return ()
  where
    word8 = fromIntegral . ord

filterUc :: Monad m => Conduit BS.ByteString m BS.ByteString
filterUc = U.conduitState
           ()
           (\() str -> return $ U.StateProducing () [ucString str])
           (\() -> return [])
  where
    uc :: Word8 -> Word8
    uc = fromIntegral . ord . toUpper . chr . fromIntegral
    ucString :: BS.ByteString -> BS.ByteString
    ucString = BS.map uc

SourceSink$$で合体させると処理が走り、何らかの値を出力する。ここではsourceHandlesinkHandleを使ってHandleベースのごく自然なSourceSinkを作って動かしてる。mは任意のモナドでいいのだけど、IO扱う時はResourceTを要求される。Conduitがフィルタ的なもので、SourceSinkの間に好きなだけ挟める。今回みたいにmIOをベースとしたモナドなら色々できるはず。

Conduitを間に挟む場合は*nixの|ほど単純ではなく、型の都合で$==$=$=を使い分けないとならない。とはいえ、Source $= Conduit == Source、Conduit =$ Sink == Sink、Conduit =$= Conduit == Conduit ってだけだから、ま、そんな苦じゃないはず(=のつく方にConduit(導管)を置くって覚えればいいだけ)。

一応実行してみると以下の通り。

% runhaskell conduit.hs
abcdefg
ABCDEFG
This is Haskell.
THIS IS HASKELL

自分でconduit定義する時はstateConduitを使うのが常套手段なのかな。あと、複数個のストリーム扱う時はどうすんだろ。

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1