21
Streaming data processing ライブラリの紹介 (主に conduit) KrdLab (2013/12/21)

Streaming data processing ライブラリの紹介 (主に Conduit)

  • Upload
    krdlab

  • View
    418

  • Download
    1

Embed Size (px)

DESCRIPTION

「名前は聞いたことがあるけど,どういうものなの?」という方向けの資料です.

Citation preview

Page 1: Streaming data processing ライブラリの紹介 (主に Conduit)

Streaming data processing ライブラリの紹介(主に conduit)

KrdLab(2013/12/21)

Page 2: Streaming data processing ライブラリの紹介 (主に Conduit)

はじめに

ときどきコードが出てきますが

「ふーん,こんな感じなのか」

って見てもらえれば幸いです

Page 3: Streaming data processing ライブラリの紹介 (主に Conduit)

今回の内容

これは何?

何があるの?

Conduit の紹介

ほんの少しだけ中身をのぞくと…

まとめ

Page 4: Streaming data processing ライブラリの紹介 (主に Conduit)

Streaming data processing ライブラリって何?

ストリームデータに対して統一インタフェースを提供 どこから来たデータであっても同じように扱える

リソースの解放をコントロール lazy IO の問題を解決

Page 5: Streaming data processing ライブラリの紹介 (主に Conduit)

統一されたインタフェース

ソケット/ファイル/メモリ,どこから来たデータなのかに関係なく扱える データの生成/変換/消費

これらを記述する primitive

これらを連結する operator

ライブラリごとに若干名前が異なりますが… Source/Process

Source/Conduit/Sink

Pipe/Proxy

InputStream/OutputStream

-- だいたいこんな感じ

run $ source (ope) process (ope) ...

ストリームデータの抽象化

Page 6: Streaming data processing ライブラリの紹介 (主に Conduit)

リソースの解放をコントロール (1/2)

lazy IO のみで構成すると大きなデータでもコンスタントなメモリで処理できる

しかし,lazy IO はリソース解放のタイミングが難しい GC 任せにすると解放タイミングが非決定的

かといって完璧に管理するのも大変

例えば hGetContents の返す String はすべてのデータを表す えっ!?

引き回しはじめたらどこで閉じたら良いのかわからない…

-- 単純かつ極端な例 (もちろんコンパイルは通る)

main = dos <- withFile “test.txt” ReadMode hGetContentsputStr s -- あっ… 表示されない…

(参考) http://www.haskell.org/haskellwiki/Iteratee_I/O

Page 7: Streaming data processing ライブラリの紹介 (主に Conduit)

リソースの解放をコントロール (2/2)

リソースは使い終わったら即時回収 リソースは貴重品

もちろん “constant memory”

“deterministic resource handling”

“resource and exception safety”

main = runResource $sourceFile “test.txt” $$ sinkHandle stdout

Page 8: Streaming data processing ライブラリの紹介 (主に Conduit)

有名どころの Implementasions

conduit Yesod の作者が作っている

ResourceT でリソース管理

pipes よく conduit と一緒に取り上げられ,確か conduit の実装に影響を与えていたはず

リソースのあたりは pipes-safe

io-streams 他と少し毛色が違う,IO をベースとした API

リソースのあたりは catch/bracket/with*

あと machines というものもあるよ!

Page 9: Streaming data processing ライブラリの紹介 (主に Conduit)

今回のターゲット

conduit について紹介します

machines についてはブログ参照 「Haskell の machines に入門してみた,というお話」

http://krdlab.hatenablog.com/entry/2013/03/16/204039

Page 10: Streaming data processing ライブラリの紹介 (主に Conduit)

Conduit: リスト操作

-- List の例

import Data.Conduitimport qualified Data.Conduit.List as CL

main = dol <- CL.sourceList [1..10] $$ CL.map (+1) =$ CL.consumeprint l

-- [2,3,4,5,6,7,8,9,10,11]

Page 11: Streaming data processing ライブラリの紹介 (主に Conduit)

Conduit: ファイル操作

宣言的

加工したい場合も宣言的にかける

main = runResourceT $sourceFile “test.txt” $$ sinkFile “output.txt”

main = runResourceT $sourceFile “test.txt”$= decode utf8$= CL.map toUpper$= encode utf8$$ sinkFile “output.txt”

Page 12: Streaming data processing ライブラリの紹介 (主に Conduit)

Conduit: Core & Generalized Types

type Source m o データの生産

type Conduit i m o データの変換

type Sink i データの消費

一般化したやつ type Producer m o

type Consumer i m r

(補足:上 3 つと違って input/output が forall)

Page 13: Streaming data processing ライブラリの紹介 (主に Conduit)

Conduit: Operators

各コンポーネントをつなぐ

($$) :: Source m a -> Sink a m b -> m b connect

($=) :: Source m a -> Conduit a m b -> Source m b fuse

(=$) :: Conduit a m b -> Sink b m c -> Sink a m c fuse

(=$=) :: Conduit a m b -> ConduitM b c m r -> ConduitM a c m r fuse

Page 14: Streaming data processing ライブラリの紹介 (主に Conduit)

Conduit: Primitives

自分で中身を書きたいときに使う

await :: Monad m => Consumer i m (Maybe i) 上流からの入力を待つ

yield :: Monad m => o -> ConduitM i o m () 値を下流へ流す

leftover :: i -> ConduitM i o m () 入力の読み残しを次に渡す

Page 15: Streaming data processing ライブラリの紹介 (主に Conduit)

Conduit: Primitives の利用例

リストを加工する例

Page 16: Streaming data processing ライブラリの紹介 (主に Conduit)

Conduit: Internal (少しだけです)

Page 17: Streaming data processing ライブラリの紹介 (主に Conduit)

Conduit: Internal

data Pipe l i o u m r l: left over (otherwise Void)

i: input values

o: output values

u: upstream からの戻り値

m: ベースモナド (ex. IO)

r: 最終的な戻り値

コンストラクタは 5 種類 HaveOutput/NeedInput/Done/PipeM/Leftover

Page 18: Streaming data processing ライブラリの紹介 (主に Conduit)

Conduit: Internal - Core datatype

data ConduitM i o m r i: input values

o: output values

m: ベースモナド (最終的に返されるコンテキスト)

r: 最終的な戻り値

内部には Pipe を持っている newtype ConduitM i o m r = ConduitM { unConduitM :: Pipe i i o () m r }

Page 19: Streaming data processing ライブラリの紹介 (主に Conduit)

Conduit: Internal - Types

type Source m o = ConduitM () o m ()

type Conduit i m o = ConduitM i o m ()

type Sink i = ConduitM i Void

type Producer m o = forall i. ConduitM i o m ()

type Consumer i m r = forall o. ConduitM i o m r

すべてが Pipe

Page 20: Streaming data processing ライブラリの紹介 (主に Conduit)

Conduit: 要するに

ストリームデータを Pipe 構造に変換

処理を Pipe で記述

演算子で連結

Conduit の処理は Pipe を interpret する

Page 21: Streaming data processing ライブラリの紹介 (主に Conduit)

まとめ

良い感じにストリームデータを扱える 統一されたインタフェース

リソース解放のコントロール

いろいろ実装あるけど,今回は conduit を紹介した

良い感じでコンポーネントを書くための primitive も提供されている

内部は Pipe を処理している

すぐに試してみたい人は “FP Haskell Center” を使うと楽です https://www.fpcomplete.com/