SlideShare une entreprise Scribd logo
1  sur  102
Télécharger pour lire hors ligne
並行プログラミングと
継続モナド
関数型言語交流会 2015-09-13
@ruicc
だれ
• @ruicc
• サーバサイドエンジニア
• Haskeller
言いたいこと
• 継続モナドが新しいモジュラリティを与えてくれる
• 並行プログラミングで継続モナド便利
3
言いたいこと(裏)
• みんな並行プログラミングしようぜ!
• 知見がもっと欲しい
4
プロローグ
並列並行Haskell本
• Simon Marlow著
• 素晴らしい本なので
• とりあえず読みましょう
• 以降heyhey Haskell本と呼ぶ
12章:並行ネットワークサーバ
• 単純でスケーラブルなチャットサーバ実装
• telnetでアクセスして、部屋へ入り、チャットする
7
とりあえず実装/改良してみた
• 局所的に問題を解いていくコード
• すごい参考になる
• IO版、Cont版作って単純ベンチマーク
• VM RAM3GB
• 9000clientsさばく
• エラーなし
• profile見たらほとんど文字列でメモリ消費してた
• OOMKillerにやられた
8
例: main周辺
9
main :: IO ()
main = withSocketsDo $ do
server <- newServer
sock <- listenOn (PortNumber (fromIntegral port))
forever $ do
(handle, host, port) <- accept sock
forkFinally
(talk handle server)
(_ -> hClose handle)
main :: IO ()
main = withSocketsDo $ do
server <- newServer
sock <- listenOn (PortNumber (fromIntegral port))
forever $ do
(handle, host, port) <- accept sock
forkFinally
(talk handle server)
(_ -> hClose handle)
Portのlisten
例: main周辺
10
main :: IO ()
main = withSocketsDo $ do
server <- newServer
sock <- listenOn (PortNumber (fromIntegral port))
forever $ do
(handle, host, port) <- accept sock
forkFinally
(talk handle server)
(_ -> hClose handle)
Portのlisten
accept
例: main周辺
11
main :: IO ()
main = withSocketsDo $ do
server <- newServer
sock <- listenOn (PortNumber (fromIntegral port))
forever $ do
(handle, host, port) <- accept sock
forkFinally
(talk handle server)
(_ -> hClose handle)
Portのlisten
accept
accept毎にfork
例: main周辺
12
main :: IO ()
main = withSocketsDo $ do
server <- newServer
sock <- listenOn (PortNumber (fromIntegral port))
forever $ do
(handle, host, port) <- accept sock
forkFinally
(talk handle server)
(_ -> hClose handle)
Portのlisten
accept
accept毎にfork
その後やること
例: main周辺
13
main :: IO ()
main = withSocketsDo $ do
server <- newServer
sock <- listenOn (PortNumber (fromIntegral port))
forever $ do
(handle, host, port) <- accept sock
forkFinally
(talk handle server)
(_ -> hClose handle)
問題点
14
その後やることが直に埋め込まれている
その後やること
並行プログラミング
並列性と並行性
• 並列性
• 計算をより速くするために資源(CPUコア等)
を用いる
• 基本的に決定的計算(純粋計算)
• 並行性
• 複数のスレッドを用いてプログラムを構築する
• 非決定的(各スレッド上でIOが発生)
16
なぜ並行プログラミングか
• プログラムの構造がシンプルになる場合がある
• スレッド単位で処理を構築し、それらを組み合わせ
るというモジュラリティを提供する (heyhey
Haskell本より)
17
並行プログラミングは
設計の問題である
並行プログラミングの難しさ
• スレッド単位で構築し、それらを組み合わせる
• スレッド毎の処理は単純にかける
• 組み合わせる箇所が難しい
19
今日はスレッドの組み
合わせの話ではない
並行プログラミングの難しさ
• スレッド同士を組み合わせるのが難しい?
• 共有メモリの操作を安全に合成出来る
• STMモナド(モナドが重要)
21
並列並行Haskell本を読もう!
• 並行モデル
• 共有メモリモデル
• トランザクションモデル
(STM)
• アクターモデル
• 例外
• 詳しく書いてある
今日はさらに細かいコードの
モジュラリティの話
Chatサーバを実装してみて
• すべてのコードがほぼ一直線の数珠繋ぎになっている
ことに気づいた
• どこを切り出してもその後の処理が全て付いてくる
• これでは再利用やテストがしにくい、なぜそうなって
いる?
24
なぜコードが一直線なのか?
• サンプル用のコードだから
• 問題を局所に押し込めて解くスタイル
• 非同期例外の存在
25
「問題を局所に押し込める」
• 例えば後始末が必要なリソースの扱い
• もし後始末がコード内に散らばってしまうと…
• コードが読みづらい/把握が難しい
• エンバグしやすい
• 保守がつらい
• 拡張しづらい
26
例外を用いる
• 何かする時に後始末も同時に書いてしまう
• 以降後始末は考えなくても良い
27
例外例:チャットルームへ入る
28
readName = do
hPutStrLn handle "What is your name?"
name <- hGetLine handle
if null name
then readName
else mask $ restore -> do -- <1>
ok <- checkAddClient server name handle
case ok of
Nothing -> restore $ do -- <2>
hPrintf handle
"The name %s is in use, Choose anothern"
name
readName
Just client ->
restore (runClient server client) -- <3>
`finally` removeClient server name
readName = do
hPutStrLn handle "What is your name?"
name <- hGetLine handle
if null name
then readName
else mask $ restore -> do -- <1>
ok <- checkAddClient server name handle
case ok of
Nothing -> restore $ do -- <2>
hPrintf handle
"The name %s is in use, Choose anothern"
name
readName
Just client ->
restore (runClient server client) -- <3>
`finally` removeClient server name
チャットルームへ入る
例外例:チャットルームへ入る
29
例外例:チャットルームへ入る
30
readName = do
hPutStrLn handle "What is your name?"
name <- hGetLine handle
if null name
then readName
else mask $ restore -> do -- <1>
ok <- checkAddClient server name handle
case ok of
Nothing -> restore $ do -- <2>
hPrintf handle
"The name %s is in use, Choose anothern"
name
readName
Just client ->
restore (runClient server client) -- <3>
`finally` removeClient server name
例外処理
readName = do
hPutStrLn handle "What is your name?"
name <- hGetLine handle
if null name
then readName
else mask $ restore -> do -- <1>
ok <- checkAddClient server name handle
case ok of
Nothing -> restore $ do -- <2>
hPrintf handle
"The name %s is in use, Choose anothern"
name
readName
Just client ->
restore (runClient server client) -- <3>
`finally` removeClient server name
入った後の処理
例外例:チャットルームへ入る
31
readName = do
hPutStrLn handle "What is your name?"
name <- hGetLine handle
if null name
then readName
else mask $ restore -> do -- <1>
ok <- checkAddClient server name handle
case ok of
Nothing -> restore $ do -- <2>
hPrintf handle
"The name %s is in use, Choose anothern"
name
readName
Just client ->
restore (runClient server client) -- <3>
`finally` removeClient server name
その後の処理が
全て付いてくる
例外例:チャットルームへ入る
32
例外で得たもの、失ったもの
• 例外を用いると、局所に問題を閉じ込め、安全にプ
ログラムを書ける
• 閉じ込められるかどうかは問題による
• 例外を用いると、コードの構造が大きく制限される
33
例外でどう制限されるか?
• 例外を使ったら
• もぐるしかなくなる
• 例外スコープが必要なくなるまで
34
例外構文による制限(余談)
• Haskellでは例外機構は関数で提供されている
• 例外が構文になっている場合、厄介に思われるかも
しれない
• 関数が第1級ならbracketを用意すると便利
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
35
そもそも例外機構は必要か?
• 一般に必要かどうかは難しい問題
• 型システムで代替できないか?
• 無理
• 型システム外から飛んでくる例外が存在する
• つまり静的には捉えられないモノの存在
36
非同期例外(GHC)
• 型システムで捉えられない例外の一つ
• よってIO上で捕まえるしかない
• スレッドの外から飛んでくる例外
• ユーザの投げるシグナル
• メモリ不足等によって発生する例外
• スレッドを外から殺すための例外
• タイムアウト実装に利用する
37
非同期例外の存在(GHC)
• 常に例外が飛んでくる可能性がある
• 非同期例外を受け取らないスコープの必要性
(mask)
• 例外補足の必要性
• 先と同様にコードが制限される
38
例外の制限の回避は?
• 例外は(少なくともGHCでは)使わないといけないこ
とがわかった
• 例外を用いるとその後に実行することがプログラム
(関数)内に直に埋め込まれてしまう
• どうする?
39
高階関数を使う
• 関数型言語(!!)なので高階関数が使える
• その後にすることを引数で渡す
40
readName = do
hPutStrLn handle "What is your name?"
name <- hGetLine handle
if null name
then readName
else mask $ restore -> do -- <1>
ok <- checkAddClient server name handle
case ok of
Nothing -> restore $ do -- <2>
hPrintf handle
"The name %s is in use, Choose anothern"
name
readName
Just client ->
restore (runClient server client) -- <3>
`finally` removeClient server name
その後の処理
その後の処理の高階関数化
41
readName' cont = do
hPutStrLn handle "What is your name?"
name <- hGetLine handle
if null name
then readName
else mask $ restore -> do -- <1>
ok <- checkAddClient server name handle
case ok of
Nothing -> restore $ do -- <2>
hPrintf handle
"The name %s is in use, Choose anothern"
name
readName
Just client ->
restore (cont server client) -- <3>
`finally` removeClient server name
その後の処理
その後の処理の高階関数化
42
引数で渡す
高階関数化によって
• 例外使うたびに似たような特殊な高階関数がたくさ
ん出来る
• うまく扱う方法はないか?
43
readName' :: (Server -> Client -> IO ()) -> IO ()
そこで継続モナドですよ
継続モナド
モナド?
モナドとは(Haskell)
• 「モナド則を満たすもの」
47
モナド則とは(Haskell)
• Monad mとそのメソッド(>>=), returnに対して以
下が成立すること
1. return x >>= f ≡ f x
2. m >>= return ≡ m
3. (m >>= f) >>= g ≡
m >>= (x -> f x >>= g)
48
モナドとは(Haskell)
• さっきのモナド則を満たす任意のものはモナド
49
モナド則の実用上の意味
• returnは何もしないアクション(モナド則1,2)
• (>>=)は二つのアクションを組み合わせる
• アクションの組み合わせ方は結合的(モナド則3)
50
整数の積の結合則
(X * Y) * Z == X * (Y * Z)
モナド則の嬉しさ
• IOアクション3つ(act1, act2, act3)を考える
• act1 :: IO A
• act2 :: A -> IO B
• act3 :: B -> IO C
• これらの組み合わせは2通りの構造が考えられる
• (act1 >>= act2) >>= act3
• act1 >>= (b -> act2 b >>= act3)
• モナド則3より、これら2構造は同一のものとして扱っ
て良い
51
モナド則の嬉しさ(2)
• IOアクションn個(act1, act2, ... ,actn)を考える
• act1 :: IO A
• act2 :: A -> IO B
...
• actn :: X -> IO Y
• これらの組み合わせはX通りの構造が考えられる
• (...(act1 >>= act2) >>= ... >>= actn)
• モナド則3より、これらX個の構造は同一のものとして
扱って良い
52
モナド則の嬉しさ(3)
• 複数の異なる構造を同一視して良い
➡ 構造の複雑さが軽減される
53
モナド則の嬉しさ(補足)
• パフォーマンス(動的性能)が同じとは言ってない
• 一般に、同じ結果になるプログラムが複数通りあっ
たらどれかが速い
54
代数的性質の嬉しさ
• みんな沢山知ってる代数的性質
• 交換則
• X * Y == Y * X
• 分配則
• X * (Y + Z) == X * Y + X * Z
• 結合則
• (X * Y) * Z == X * (Y * Z)
• 上記はどれも複数の構造を同一視して良い性質
• 複雑さと戦うための武器の一つ
55
そして圏論へ
• 数学史に現れてきた代数的構
造をいろいろ包含する概念圏
を扱う
• プログラムの複雑さと戦おう
• 9/9発売
そして圏論へ
• 数学史に現れてきた代数的構
造をいろいろ包含する概念圏
を扱う
• プログラムの複雑さと戦おう
• 9/19発売
継続モナド
継続モナドのアクション
newtype Cont r a = Cont { runCont :: (a -> r) -> r }
type Cont' r a = (a -> r) -> r
• 関数を受け取って結果を返す関数、というアクション
• 引数の関数はアクションの最後で実行される
59
継続?
継続とは
• 「その後に実行すること」
61
62
newtype Cont r a = Cont { runCont :: (a -> r) -> r }
• 関数を受け取って結果を返す関数、というアクション
• 引数の関数はアクションの最後で実行される
継続モナドのアクション(再)
継続
継続
• 継続 =「その後に実行すること」が表現されている
継続
継続モナドの定義
instance Monad (ContT r m) where
return x = ContT ($ x)
m >>= k =
ContT $ c -> runContT m (x -> runContT (k x) c)
63
継続モナドの定義
instance Monad (ContT r m) where
return x = ContT ($ x)
m >>= k =
ContT $ c -> runContT m (x -> runContT (k x) c)
64
mを走らせる
mに渡す継続
継続モナドの定義
instance Monad (ContT r m) where
return x = ContT ($ x)
m >>= k =
ContT $ c -> runContT m (x -> runContT (k x) c)
65
(k x)を走らせる
(k x)に渡す継続xはmが渡す
継続モナドの定義
instance Monad (ContT r m) where
return x = ContT ($ x)
m >>= k =
ContT $ c -> runContT m (x -> runContT (k x) c)
66
全体の結果はアクションを返す
継続cは外からもらう
(k x)に渡す継続
継続モナド例(trivial)
action1, action2, action3 :: Cont r Int
action1 = return 42
action2 = return 13
action3 = return 2
cont_ex = do
x <- action1
y <- action2
z <- action3
return (x + y + z)
67
action1の継続は
どれか?
継続モナド例(trivial)
action1, action2, action3 :: Cont r Int
action1 = return 42
action2 = return 13
action3 = return 2
cont_ex = do
x <- action1
y <- action2
z <- action3
return (x + y + z)
68
action1の継続
(action1後に実行)
69
action1, action2, action3 :: Cont r Int
action1 = return 42
action2 = return 13
action3 = return 2
cont_ex = do
x <- action1
y <- action2
z <- action3
return (x + y + z)
継続モナド例(trivial)
action2の継続
(action2後に実行)
70
action1, action2, action3 :: Cont r Int
action1 = return 42
action2 = return 13
action3 = return 2
cont_ex = do
x <- action1
y <- action2
z <- action3
return (x + y + z)
継続モナド例(trivial)
action3の継続
(action3後に実行)
71
cont_ex = do
x <- action1
y <- action2
z <- action3
return (x + y + z)
main = do
print $ runCont cont_ex id
継続モナド例(trivial)
最後に実行される
継続
つまりどういうこと?
• 継続モナドを使うと
• アクションが並べた順に実行される
72
IOと何が違うのか?
• CPS(Continuation Passing Style)
• スタイルが違う
• できることは同じ
73
継続モナドの動的性能
• 同じことができるプログラムは、一般にどちらかが
速い
• 継続モナドやCPSを使うと速くなることがある
• 継続モナドはクロージャを大量に生成する
• GC頻度が上がるかも
74
継続モナドの他の特徴
はどうなのか?
継続モナドと例外
例外の補足
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
77
例外の補足
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
78
リソース取得
リソース解放
(必ず実行される) アクション
bracketとは
• 関数化された例外機構
• 例外構文を持たないだけで、同様の特徴を持つ
• コード構造が限定される
• とはいえそれでも便利
79
例外の補足
bracket :: IO a -> (a -> IO b) -> (a -> IO c) -> IO c
80
継続っぽい!
簡単な例
81
bracket_demo :: ContT r IO Int
bracket_demo = do
fh <- ContT $ bracket
(openFile "tmp" WriteMode)
hClose
n <- ContT $ bracket
(hPutStrLn fh "Gain 42" >> return 42)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
l <- ContT $ bracket
(hPutStrLn fh "Gain 13" >> return 13)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
liftIO $ throwIO (ErrorCall "heyhey")
return $ n + l
簡単な例
82
bracket_demo :: ContT r IO Int
bracket_demo = do
fh <- ContT $ bracket
(openFile "tmp" WriteMode)
hClose
n <- ContT $ bracket
(hPutStrLn fh "Gain 42" >> return 42)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
l <- ContT $ bracket
(hPutStrLn fh "Gain 13" >> return 13)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
liftIO $ throwIO (ErrorCall "heyhey")
return $ n + l
ContT r IO a
簡単な例
83
bracket_demo :: ContT r IO Int
bracket_demo = do
fh <- ContT $ bracket
(openFile "tmp" WriteMode)
hClose
n <- ContT $ bracket
(hPutStrLn fh "Gain 42" >> return 42)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
l <- ContT $ bracket
(hPutStrLn fh "Gain 13" >> return 13)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
liftIO $ throwIO (ErrorCall "heyhey")
return $ n + l
bracketを
継続モナドアクションに
簡単な例
84
bracket_demo :: ContT r IO Int
bracket_demo = do
fh <- ContT $ bracket
(openFile "tmp" WriteMode)
hClose
n <- ContT $ bracket
(hPutStrLn fh "Gain 42" >> return 42)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
l <- ContT $ bracket
(hPutStrLn fh "Gain 13" >> return 13)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
liftIO $ throwIO (ErrorCall "heyhey")
return $ n + l
例外機構を
(ネストではなく)
縦に並べている
簡単な例
85
bracket_demo :: ContT r IO Int
bracket_demo = do
fh <- ContT $ bracket
(openFile "tmp" WriteMode)
hClose
n <- ContT $ bracket
(hPutStrLn fh "Gain 42" >> return 42)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
l <- ContT $ bracket
(hPutStrLn fh "Gain 13" >> return 13)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
liftIO $ throwIO (ErrorCall "heyhey")
return $ n + l
わざと例外を投げる
さてどう動くか?
86
bracket_demo :: ContT r IO Int
bracket_demo = do
fh <- ContT $ bracket
(openFile "tmp" WriteMode)
hClose
n <- ContT $ bracket
(hPutStrLn fh "Gain 42" >> return 42)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
l <- ContT $ bracket
(hPutStrLn fh "Gain 13" >> return 13)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
liftIO $ throwIO (ErrorCall "heyhey")
return $ n + l
動作
87
bracket_demo :: ContT r IO Int
bracket_demo = do
fh <- ContT $ bracket
(openFile "tmp" WriteMode)
hClose
n <- ContT $ bracket
(hPutStrLn fh "Gain 42" >> return 42)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
l <- ContT $ bracket
(hPutStrLn fh "Gain 13" >> return 13)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
liftIO $ throwIO (ErrorCall "heyhey")
return $ n + l
順々にリソース取得が
実行される
動作
88
bracket_demo :: ContT r IO Int
bracket_demo = do
fh <- ContT $ bracket
(openFile "tmp" WriteMode)
hClose
n <- ContT $ bracket
(hPutStrLn fh "Gain 42" >> return 42)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
l <- ContT $ bracket
(hPutStrLn fh "Gain 13" >> return 13)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
liftIO $ throwIO (ErrorCall "heyhey")
return $ n + l
例外が投げられる
動作
89
bracket_demo :: ContT r IO Int
bracket_demo = do
fh <- ContT $ bracket
(openFile "tmp" WriteMode)
hClose
n <- ContT $ bracket
(hPutStrLn fh "Gain 42" >> return 42)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
l <- ContT $ bracket
(hPutStrLn fh "Gain 13" >> return 13)
(n -> hPutStrLn fh $ "Finalize: " ++ show n)
liftIO $ throwIO (ErrorCall "heyhey")
return $ n + l
逆順でfinalizerが
実行される
どういうこと?
• 継続モナド上(ContT r IO a)では例外はアクションの
逆順で伝播する
90
継続モナドのアクション
newtype ContT r m a =
ContT { runContT :: (a -> m r) -> m r }
•継続はアクションの最後に実行される
•継続内で例外が発生したら、アクションに戻ってくる
•つまり、例外はアクションを逆順に伝播する
91
継続モナドと例外
• 継続モナドによって例外機構の制約から抜けること
が出来た
• モナドなのでアクションが組み合わせやすい
92
継続モナドを考える
• 継続モナドは新しいモジュラリティを提供する
93
関数呼び出しイメージ
94
f
g
hcall
call
return
return
関数呼び出しイメージ
95
f
g
hcall
call
return
return
使いまわせる粒度
継続モナドイメージ
96
f
g
h
tail call
tail call
継続モナドイメージ
97
f
g
h
tail call
tail call
使いまわせる粒度
使いまわせる粒度
使いまわせる粒度
継続モナドと例外イメージ
98
f
g
h
call
call
finalizer
finalizer
継続モナドと例外イメージ
99
f
g
h
call
call
finalizer
finalizer
使いまわせる粒度
使いまわせる粒度
使いまわせる粒度
まとめ
• Haskellでは並行プログラミングに例外は必須
• 例外を使うとコード構造に制約ができる
• 継続モナドで例外が頻発するコードでもモジュラリ
ティを高く保つことができる
100
エピローグ
101
-- sketch
launchServer :: Port -> IO ()
launchServer port = (`runContT` return) $ do
client <- ContT $ acceptLoop port
loginedClient <- ContT $ login client
roomId <- ContT $ joinRoom loginedClient
ContT $ chat loginedClient roomId
エピローグ
102
-- Add logger
launchServer :: Port -> IO ()
launchServer port = (`runContT` return) $ do
logger <- newLogger
client <- ContT $ acceptLoop port
loginedClient <- ContT $ login client
roomId <- ContT $ joinRoom loginedClient
ContT $ chat loginedClient roomId logger

Contenu connexe

Tendances

闇魔術を触ってみた
闇魔術を触ってみた闇魔術を触ってみた
闇魔術を触ってみた
Satoshi Sato
 
数式を綺麗にプログラミングするコツ #spro2013
数式を綺麗にプログラミングするコツ #spro2013数式を綺麗にプログラミングするコツ #spro2013
数式を綺麗にプログラミングするコツ #spro2013
Shuyo Nakatani
 
プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法
Takuya Akiba
 

Tendances (20)

C++ マルチスレッドプログラミング
C++ マルチスレッドプログラミングC++ マルチスレッドプログラミング
C++ マルチスレッドプログラミング
 
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
SQLアンチパターン 幻の第26章「とりあえず削除フラグ」
 
中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr中3女子が狂える本当に気持ちのいい constexpr
中3女子が狂える本当に気持ちのいい constexpr
 
AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解AVX-512(フォーマット)詳解
AVX-512(フォーマット)詳解
 
Glibc malloc internal
Glibc malloc internalGlibc malloc internal
Glibc malloc internal
 
Pythonによる黒魔術入門
Pythonによる黒魔術入門Pythonによる黒魔術入門
Pythonによる黒魔術入門
 
たのしい高階関数
たのしい高階関数たのしい高階関数
たのしい高階関数
 
例外設計における大罪
例外設計における大罪例外設計における大罪
例外設計における大罪
 
yieldとreturnの話
yieldとreturnの話yieldとreturnの話
yieldとreturnの話
 
PostgreSQLアンチパターン
PostgreSQLアンチパターンPostgreSQLアンチパターン
PostgreSQLアンチパターン
 
ヤフー社内でやってるMySQLチューニングセミナー大公開
ヤフー社内でやってるMySQLチューニングセミナー大公開ヤフー社内でやってるMySQLチューニングセミナー大公開
ヤフー社内でやってるMySQLチューニングセミナー大公開
 
新しい並列for構文のご提案
新しい並列for構文のご提案新しい並列for構文のご提案
新しい並列for構文のご提案
 
闇魔術を触ってみた
闇魔術を触ってみた闇魔術を触ってみた
闇魔術を触ってみた
 
関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐり関数型プログラミングのデザインパターンひとめぐり
関数型プログラミングのデザインパターンひとめぐり
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
 
Rustに触れて私のPythonはどう変わったか
Rustに触れて私のPythonはどう変わったかRustに触れて私のPythonはどう変わったか
Rustに触れて私のPythonはどう変わったか
 
SQLアンチパターン - ナイーブツリー
SQLアンチパターン - ナイーブツリーSQLアンチパターン - ナイーブツリー
SQLアンチパターン - ナイーブツリー
 
数式を綺麗にプログラミングするコツ #spro2013
数式を綺麗にプログラミングするコツ #spro2013数式を綺麗にプログラミングするコツ #spro2013
数式を綺麗にプログラミングするコツ #spro2013
 
プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法プログラミングコンテストでの動的計画法
プログラミングコンテストでの動的計画法
 
純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門純粋関数型アルゴリズム入門
純粋関数型アルゴリズム入門
 

Similaire à 並行プログラミングと継続モナド

すごいH 第12章モノイド
すごいH 第12章モノイドすごいH 第12章モノイド
すごいH 第12章モノイド
Shinta Hatatani
 
シェル芸初心者によるシェル芸入門 (修正版)
シェル芸初心者によるシェル芸入門 (修正版)シェル芸初心者によるシェル芸入門 (修正版)
シェル芸初心者によるシェル芸入門 (修正版)
icchy
 
Haskell勉強会 14.1〜14.3 の説明資料
Haskell勉強会 14.1〜14.3 の説明資料Haskell勉強会 14.1〜14.3 の説明資料
Haskell勉強会 14.1〜14.3 の説明資料
Etsuji Nakai
 
プログラミングHaskell(第1章)
プログラミングHaskell(第1章)プログラミングHaskell(第1章)
プログラミングHaskell(第1章)
yaju88
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxps
MITSUNARI Shigeo
 
K010 appstat201201
K010 appstat201201K010 appstat201201
K010 appstat201201
t2tarumi
 
Web本文抽出 using crf
Web本文抽出 using crfWeb本文抽出 using crf
Web本文抽出 using crf
Shuyo Nakatani
 

Similaire à 並行プログラミングと継続モナド (20)

モナドをつくろう
モナドをつくろうモナドをつくろう
モナドをつくろう
 
すごいH 第12章モノイド
すごいH 第12章モノイドすごいH 第12章モノイド
すごいH 第12章モノイド
 
シェル芸初心者によるシェル芸入門 (修正版)
シェル芸初心者によるシェル芸入門 (修正版)シェル芸初心者によるシェル芸入門 (修正版)
シェル芸初心者によるシェル芸入門 (修正版)
 
フラグを愛でる
フラグを愛でるフラグを愛でる
フラグを愛でる
 
Haskell勉強会 in ie
Haskell勉強会 in ieHaskell勉強会 in ie
Haskell勉強会 in ie
 
Haskell勉強会 14.1〜14.3 の説明資料
Haskell勉強会 14.1〜14.3 の説明資料Haskell勉強会 14.1〜14.3 の説明資料
Haskell勉強会 14.1〜14.3 の説明資料
 
Unix
UnixUnix
Unix
 
JavaScript 講習会 #1
JavaScript 講習会 #1JavaScript 講習会 #1
JavaScript 講習会 #1
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
 
MoteMote Compiler Plugin
MoteMote Compiler PluginMoteMote Compiler Plugin
MoteMote Compiler Plugin
 
Objc lambda
Objc lambdaObjc lambda
Objc lambda
 
関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)関数型言語&形式的手法セミナー(3)
関数型言語&形式的手法セミナー(3)
 
プログラミングHaskell(第1章)
プログラミングHaskell(第1章)プログラミングHaskell(第1章)
プログラミングHaskell(第1章)
 
条件分岐とcmovとmaxps
条件分岐とcmovとmaxps条件分岐とcmovとmaxps
条件分岐とcmovとmaxps
 
mxnetで頑張る深層学習
mxnetで頑張る深層学習mxnetで頑張る深層学習
mxnetで頑張る深層学習
 
Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7Pfi Seminar 2010 1 7
Pfi Seminar 2010 1 7
 
asm.js x emscripten: The foundation of the next level Web games
asm.js x emscripten: The foundation of the next level Web gamesasm.js x emscripten: The foundation of the next level Web games
asm.js x emscripten: The foundation of the next level Web games
 
K010 appstat201201
K010 appstat201201K010 appstat201201
K010 appstat201201
 
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
How wonderful to be (statically) typed 〜型が付くってスバラシイ〜
 
Web本文抽出 using crf
Web本文抽出 using crfWeb本文抽出 using crf
Web本文抽出 using crf
 

Plus de Kousuke Ruichi (7)

grpc-haskell.pdf
grpc-haskell.pdfgrpc-haskell.pdf
grpc-haskell.pdf
 
An engineer uses monads
An engineer uses monadsAn engineer uses monads
An engineer uses monads
 
Purescript with Monad
Purescript with MonadPurescript with Monad
Purescript with Monad
 
ゆるふわなHaskell話
ゆるふわなHaskell話ゆるふわなHaskell話
ゆるふわなHaskell話
 
Haskell Day2012 - 参照透過性とは何だったのか
Haskell Day2012 - 参照透過性とは何だったのかHaskell Day2012 - 参照透過性とは何だったのか
Haskell Day2012 - 参照透過性とは何だったのか
 
Programming haskell chapter10
Programming haskell chapter10Programming haskell chapter10
Programming haskell chapter10
 
Programming Haskell Chapter8
Programming Haskell Chapter8Programming Haskell Chapter8
Programming Haskell Chapter8
 

並行プログラミングと継続モナド