Upgrade to Pro — share decks privately, control downloads, hide ads and more …

純粋関数型言語では副作用をどう扱うのか / Side Effects in Purely Functional Languages

5f533aeab28ed4f70c26e336e71296f7?s=47 tipo159
June 06, 2017

純粋関数型言語では副作用をどう扱うのか / Side Effects in Purely Functional Languages

純粋関数型言語での副作用の扱い方としてStream-based I/OとMonadic I/Oを、純粋関数型AltJS(PureScriptとElm)での副作用の扱い方を紹介しています。
We Are JavaScripters! 8th
WeJS

5f533aeab28ed4f70c26e336e71296f7?s=128

tipo159

June 06, 2017
Tweet

Transcript

  1. 純粋関数型言語では 副作用をどう扱うのか We Are JavaScripters! 8th 2017/6/6

  2. 自己紹介 ▰ 仕事ではC++, Java等でインフラ開発 ▰ JavaScriptはHackathonへ参加するために 勉強中 ▰ 以前Alfa Romeo

    156に乗っていたので、こ の名前を使用 2 河原崎(@tipo159)
  3. アウトライン 1. 純粋関数型言語での副作用の扱い方 ▻ Stream-based I/O ▻ Monadic I/O 2.

    純粋関数型AltJSでの副作用の扱い方 ▻ PureScript ▻ Elm 3. まとめ 3
  4. 純粋関数型言語での副作用の 扱い方 4 1

  5. 5 純粋関数型言語 は副作用のある 関数を使えない 副作用がないと 実用的なプログ ラムは書けない 問題点

  6. 6 Haskellプログラム [Response] [Request] Stream-based I/Oの概念図 (Haskell 1.0) main ::

    [Response] -> [Request] 副作用をプログラムの入出力として扱う
  7. main :: [Response] -> [Request] data Request = ReadFile Name

    | WriteFile Name String | … data Response = Success | Str String | Failure IOError | … Stream-based I/Oの定義抜粋 7
  8. main :: Dialogue main ~(Success : ~((Str userInput) : ~(Success

    : ~(r4 : _)))) = [ AppendChan stdout "please type a filename\n", ReadChan stdin, AppendChan stdout name, ReadFile name, AppendChan stdout (case r4 of Str contents -> contents Failure ioerr -> "can’t open file") ] where (name : _) = lines userInput Stream-based I/Oのプログラム例 8 Requests: [AppendChan …, ReadChan …, AppendChan …, ReadFile …, AppendChan …] Response: [Success, Str userInput, Success, Str contents or Failure ioerr, Success]
  9. Stream-based I/Oの問題点 ▰ 拡張が困難: 新しいI/O操作を追加するためには 言語仕様の変更が必要 ▰ RequestとResponseの対応付けが困難: Haskellは 遅延評価のため、評価順序の遅延パターンによ

    る記述が必要 ▰ 二つのmainプログラムの合成が不可能 9
  10. 10 IO t Monadic I/Oの概念図 (Haskell 98) main:: IO ()

    type IO t = World -> (t, World) result :: t タイプ(IO t)の値は、Action 実行されるとタイプtの結果を返す前にIOを行う
  11. 11 Actionはファーストクラスオブジェクト type IO t = World -> (t, World)

    ▰ Actionはファーストクラスオブジェクト ▻ 複数Actionの合成が可能 ▰ Actionの評価(Evaluating)は作用なし ▻ 遅延評価等の評価順序とは違う概念 ▰ Actionの実行(Performing)は作用あり
  12. 12 Action合成の例 putChar getChar Char () getChar :: IO Char

    putChar :: Char -> IO () getCharとputCharを合成
  13. 13 Bindコンビネータ(>>=) [1 / 3] putChar getChar Char () (>>=)

    :: IO a -> (a -> IO b) -> IO b echo :: IO () Echo = getChar >> = putChar
  14. 14 Bindコンビネータ(>>=) [2 / 3] ▰ bindコンビネータは左側のActionの結果を右側 のActionとbindする

  15. 15 Bindコンビネータ(>>=) [3 / 3] ▰ 合成Action a >>= \x

    -> bを実行すると ▻ aを実行して結果rを提供(yield) ▻ 関数\x -> bをrに適用(apply) ▻ b{x <- r}の結果Actionを実行 ▻ 結果vを返却 b a r v x
  16. Stream-based I/Oの問題点を解決 ▰ 拡張が困難: ライブラリとして新しいモナドを追加可 能 ▰ RequestとResponseの対応付けが困難: bindコンビ ネータで、左側を先に評価することを保証

    ▰ 二つのmainプログラムの合成が不可能: bindコン ビネータで合成が可能 16
  17. 純粋関数型AltJSでの副作用の 扱い方 17 2

  18. 18 PureScript Monadic I/Oを採用 HaskellのMonadと違い、副作用の対象を明記 main:: forall e. Eff (fs

    :: FS, console:: CONSOLE | e) Unit この例ではmainはファイルシステムを使用し、 コンソールにメッセージを出力する
  19. 19 Elm The Elm Architectureに基づき、副作用はElm Runtimeで実施 ▰ The Elm ArchitectureはWebフレームワークの様なもの

    ▰ アプリケーションの状態をModelで、Modelの更新方法を Updateで、モデルの表示をViewで定義する ▰ Stream-based I/OのRequestに対応するCmdと、Responseに 対応するSubで副作用のある処理を管理
  20. 20 ElmのCmd/Subの概念図 Elm Runtime update Msg Html Cmd Sub Subで購読を指定したMsgがElm

    Runtimeから通知される
  21. Stream-based I/Oの問題点は大丈夫? 対象をフロントエンドに限定しているため問題ない ▰ 拡張が困難: 新しいI/O操作を追加する時にはThe Elm Architectureの変更が必要になるため問題ない ▰ RequestとResponseの対応付けが困難:

    遅延評価で はないため問題ない ▰ 二つのmainプログラムの合成が不可能: mainプログ ラムの合成はできなくても問題ない 21
  22. まとめ 22 3

  23. 23 まとめ ▰ 純粋関数型言語 ▻ Stream-based I/O: 副作用をプログラムの入出力に ▻ Monadic

    I/O: Actionが値となるモナドを使用 ▰ 純粋関数型AltJS ▻ PureScript: モナドを使用 ▻ Elm: Stream-based I/Oに類似したCmd/Subを使用