Communicating Haskell Process
(CHP) サーベイ
岸本 誠
Communicating Haskell Process
(CHP) とは
● 英ケント大学 School of Computing
(JCSPとかの開発元)
● Haskellベース(Embedded DSL)
特徴
●
独立性が高い
– Haskellの(標準的な)並列・並行機能とは独立
– ただし、非決定的動作を顕著にするためにはコンパイル
して並列化が必要(後述)
●
実用性が高い
– JCSPと似たような方向性(か?)
– IO と混ぜられる
– Software Transactional Memory とは
違う方向性? (混ぜられないことに意味がある)
バージョン
● 公式ページでは2010年のv2.1.0.1が最後
● 実際には2014年のv2.2.0.1がhackageに登録
●
現状、そんなに活発に開発されている状況では
ないようである → パッチが必要(次で説明)
インストール
● パッケージ(hackage)はある、が、
最新のGHC環境にcabal(パッケージ管理ツール兼
make)でインストールしようとするとエラーが出る
● ソースtarballを取ってきて展開しパッチを当て、
cabalでインストールする
( http://metanest.jp/cspken/18/patches/ で公開 )
●
定型的なコードを追加するだけなので本質的には
難しいパッチではないが、Haskellに慣れていないと
必要な情報を探すのが大変かも(記号はGoogleで
検索できない)
インストール(続)
● 入出力などは chp-plus という別パッケージなので
それもインストールする
●
こちらもパッチが必要
チュートリアル
●
チュートリアルが用意されている
– https://www.cs.kent.ac.uk/projects/ofa/chp/tutorial.pdf
●
以下ほぼチュートリアル(の前半)に沿って解説
●
(そのままでは動かないコード等の注など)
全般的な注意
● 下線 _ に関して
● Haskell では、関数等のバリエーション版に
ダッシュの意のシングルクオートや下線を多用
● mapM と mapM_ など
● チュートリアルのpdfからコピペすると、下線が全部
消える
● 特に多用の runCHP_ が runCHP になるので注意
基本的な枠組
● IO と似たような「型コンストラクタ」CHP がある
● IO が do 記法によって入出力アクションをまとめる
ように、do 記法でチャネル通信などをつなげる
● runCHP_ で IO () につなげて main から実行
– runCHP_ :: CHP a -> IO ()
例1
import Prelude (IO)
import Control.Concurrent.CHP (CHP, runCHP_)
import qualified Control.Concurrent.CHP.Common
as CHP
import Control.Concurrent.CHP.Console (
consoleProcess, ConsoleChans,
cStdin, cStdout)
main :: IO ()
main = runCHP_ (consoleProcess echo)
echo :: ConsoleChans -> CHP ()
echo chans = CHP.id (cStdin chans) (cStdout chans)
例2
import Prelude (IO, show, fromEnum, (++), mapM)
import Control.Concurrent.CHP (CHP, runCHP_,
readChannel, writeChannel)
import Control.Concurrent.CHP.Console
(ConsoleChans, consoleProcess, cStdin, cStdout)
import Control.Monad (forever)
main :: IO ()
main = runCHP_ (consoleProcess printOrd)
printOrd :: ConsoleChans -> CHP ()
printOrd chans = forever (do
x <- readChannel (cStdin chans)
let ordXStr = show (fromEnum x) ++ "n"
mapM (writeChannel (cStdout chans)) ordXStr
)
例2(続)
import Prelude (IO, show, fromEnum, (++), mapM_)
import Control.Concurrent.CHP (CHP, runCHP_,
readChannel, writeChannel)
import Control.Concurrent.CHP.Console (ConsoleChans,
consoleProcess, cStdin, cStdout)
main :: IO ()
main = runCHP_ (consoleProcess printOrd)
printOrd :: ConsoleChans -> CHP ()
printOrd chans = loop :: CHP ()
where
loop = do
x <- readChannel (cStdin chans)
let ordXStr = show (fromEnum x) ++ "n"
mapM_ (writeChannel (cStdout chans)) ordXStr
loop
選択と並列
● 選択の演算子 <-> / 並列の演算子 <||>
printOrdWhileWaiting :: ConsoleChans -> CHP ()
printOrdWhileWaiting chans =
(readChannel cin) >>= inner
where
inner :: Char -> CHP ()
inner x = do
_ <- printString (show (fromEnum x) ++ "n")
(waitFor 1000000 >> inner x) <->
(readChannel cin >>= inner)
cin = cStdin chans
cout = cStdout chans
cerr = cStderr chans
printString s
= mapM (writeChannel cout) s <||>
mapM (writeChannel cerr) s
高度な合成の例(パイプライン)
crazyPipeline :: ConsoleChans -> CHP ()
crazyPipeline chans = do
pipelineConnect [
CHP.filter isLetter,
CHP.map toUpper,
CHP.filter (/= 'X')]
(cStdin chans) (cStdout chans)
return ()
高度な合成の例(パイプライン)続
crazyPipeline chans = loop
where
loop = do
c1 <- readChannel (cStdin chans)
if isLetter c1
then bottom_half c1
else loop
bottom_half c1 = do
let c2 = toUpper c1
if c2 /= 'X'
then writeChannel (cStdout chans) c2
else loop
loop
以上で2章まで
● 3章以下
● 3章: tracing - チャネル通信にラベル付け
– コンパイルオプション-threadedを付け、マルチスレッドを
有効にしてマルチコアで並列(パラレル)に出来るように
– MPマシンでランタイムオプション+RTS -N2を付け実行
● 4章: poisoning - チャネルの通信に「毒」を入れる
と、それを受信した所(重要)でプロセスが例外に
続き
● 5章: Extended Transactions
● 6章: バリアとバッファ – バッファはプロセスで実装
● 7章: 共有チャネルとブロードキャストチャネル
● 8章: CHPモナドのモナド則
● 9章: FAQ
まとめ
● CHP(Communicating Haskell Process)は
– Haskell中のEDSL風に実装されたCSPライブラリで
– 実用性を重視しており
– 多くのプロセスパターンを試せるレベルにある
●
要注意点
– (本質的な難しさは無いが)最新の環境では、
コンパイルを通すためにパッチが必要
– チュートリアルにも、そのままでは動かないものがある
– 後日、岸本のほうから、パッチと、動くように手を入れた
チュートリアル内のコードを配布する
( http://metanest.jp/cspken/18/ )
  おわり

CHP survey