Comments
Description
Transcript
関数プログラミングの希望 Haskellの夢
関数プログラミングの希望 Haskellの夢 2012.4.17 山本和彦 1 自己紹介 山本和彦 二児の父 Haskell 歴は4年と少し Mew、Firemacs、Mighttpd の開発者 2 おしな書き 3 関数プログラミングとは何か 4 僕の定義 5 関数型言語の仲間たち 6 静的型付き関数型言語の特徴 7 部品プログラミング 8 パラダイムの違い 9 例題 入力として整数のリストあるいは配列 10, 20, 30, 40, 50 がある 0 から数えて n 番目の要素には n を掛ける それらをすべて足し合わせる つまり、以下のような計算をする 10 * 0 + 20 * 1 + 30 * 2 + 40 * 3 + 50 *4 = 400 10 Ruby で逐次&反復 inject は使わない場合 def func (ar) sum = 0; i = 0; ar.each{|x| sum += x * i; i += 1; } sum; end ← 命令の列挙 ← 命令の列挙 ← 破壊的代入 ← 破壊的代入 実行 func([10,20,30,40,50]); → 400 11 Haskell で map & reduce zip [0..] [10,20,30,40,50] → [(0,10),(1,20),(2,30),(3,40),(4,50)] map (\(i,x) -> x*i) (上記の式) → [0,20,60,120,200] foldl (+) 0 (上記の式) → ((((0 + 0) + 20) + 60) + 120) + 200 → 400 関数を合成する func = foldl (+) 0 . map (\(i,x) -> x*i) . zip [0..] func [10,20,30,40,50] → 400 12 部品プログラミング 信号処理回路のようなプログラミング 13 合成可能 (再利用可能) 関数型言語では関数が合成し易い 関数が本当に独立した部品だから クラスベースのオブジェクト指向では合成が困難 オブジェクトが環境を引きずるから 14 高いエラー検出率 15 型の神話 16 役に立つ静的型付き言語 17 関数型言語とは 「すべては式」 を活かしている言語 18 Ruby でフィボナッチ数 すべては式だけれど命令的に書ける 19 Haskell でフィボナッチ数 すべては式である 20 コンパイルはテスト あらゆる場所で式と式の型の関係が検査される 21 静的型付き関数型言語では 自然とテスト駆動となる コンパイルを通れば 型に関する間違いはない 値に関するテストは必要 22 値に関するテスト 23 おススメの書籍 Scheme 手習い 再帰を学ぶ プログラミングの基礎 関数プログラミングを学ぶ OCaml、浅井健一著 プログラミングHaskell 関数プログラミングを学ぶ Scalaスケーラブルプログラミング第2版 Java プログラマーにお勧め 24 Haskell の実用的な話題 25 Yesod とは何か? Haskell で書かれたフルスタックの Web アプリケーション・フレームワーク 26 Haskell コンパイルが通れば だいたい思い通りにプログラムが動く Yesod コンパイルが通れば だいたい思い通りに Web アプリが動く 27 Hello, world! 28 Yesod を支える技術 29 安全対策技術 30 ルーティング情報 型安全 mkYesod "HelloWorld" [parseRoutes| / HomeR GET /hello HelloR GET |] 型の自動生成 data Route = HomeR | HelloR 実際にはもっと複雑ですが... 型で守るURL @{} は Route 型を要求する getHomeR :: Handler RepHtml getHomeR = defaultLayout [whamlet| <a href=@{HelloR}>Go to hello page! |] アプリ内ではリンク切れなし! 31 Template Haskell 関数型言語ではパーサの作成が簡単 パーサコンビネータのおかげ 気軽に DSL を作れる 準クオート "[parser|" と "|]" の間に DSL を書く mkYesod "HelloWorld" [parseRoutes| / HomeR GET /hello HelloR GET |] 展開 コンパイル時に構文木を生成する data Route = HomeR | HelloR ... 型検査の対象となる 32 No No No 33 似て非なるものの区別 Echo アプリ mkYesod "HelloWorld" [parseRoutes| /echo/#Text EchoR GET |] getEchoR :: Text -> Handler RepHtml getEchoR = defaultLayout . toWidget . echoHtml echoHtml :: Text -> a -> Html echoHtml txt = [hamlet|<h1>#{txt}|] URL %3Cscript%3Ealert%28%22Danger %21%22%29%3B%3C%2Fscript%3E Text <script>alert("Danger!");</script> Html <script>alert("Danger!"); </script> 34 各種DSL Hamlet (HTML, Html 型) <h1 .page-title>#{pageTitle} <p>This is the home page of... Cassius (CSS, Css 型) #myid color: #{red} font-size: #{bodyFontSize} Julius (JavaScript, Javascript 型) $(function(){ $("section.#{sectionClass}").hide(); $("#mybutton").click(function(){ document.location = "@{SomeRouteR}"; }); ^{addBling} }); 型を考慮して変数を埋め込める(interpolate) 35 Widget 36 高速化技術 37 Yesod / Warp の速度 Ping pong ベンチマーク 38 高速文字列処理 BlazeBuiler 差分リストのアイディアに基づいた 高速に文字列を連結するライブラリ 文字列連結 Haskell の文字列は変更できないので、安全に共有できる 関数合成は O(1) 出力 出力の際に、はじめて出力バッファにコピーされる 39 Conduit とは何か? Unix のパイプに似ている 第二世代の Iteratee 40 合成可能とは何か? 悪しき一枚岩による実装 replicate :: Int -> a -> [a] replicate 0 _ = [] replicate n x = x : replicate (n - 1) x 合成による実装 replicate n x = take n $ repeat x Conduit でのファイルのコピー copyFile :: FilePath -> FilePath -> IO () copyFile src dst = runResourceT $ CB.sourceFile src $$ CB.sinkFile dst 41 Conduit での合成 42 Warp と Conduit 43 高速サーバ 高速化にはイベント駆動が必須 プロセス・プール、ネイティブ・スレッド・プールでは遅い 多くの言語ではコールバック (イベント・ハンドラ) Haskell では軽量スレッド 44 軽量スレッド ユーザ空間で実装されたスレッド ネイティブ・スレッドとは異なる 軽量 10万個作成しても大丈夫 軽量スレッドの切り替え時には、 カーネルへのコンテキスト・スイッチが発生しない Haskell に特有の機能 ライブラリはノンブロッキングとなるよう実装されている 外部言語呼び出しでブロックしても大丈夫 外部言語呼び出しにはネイティブ・スレッドを使う 非同期例外 ある軽量スレッドが、他の軽量スレッドを kill できる ほとんどの計算が純粋なので、突然例外を受け取ってもよい 45 Warp が発行するシステムコール 軽量スレッドの敵はシステムコール カーネルにコンテキストスイッチして、 すべての軽量スレッドが止まる なるべくシステムコールは発行しない stat() で得た情報などはキャッシュすべき 46 Yesod のサイト 参考文献 http://www.yesodweb.com/ Yesod のチュートリアル "Haskell web programming" http://yannesposito.com/Scratch/en/blog/ Yesod-tutorial-for-newbies/ Haskell and Yesod オライリーから近日発売 47 (STMなどの)質問は 懇親会 または @kazu_yamamoto 48