思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8

1,070 views

Published on

JJUG CCC 2017 Spring の発表スライドです。Haskell 互換なふたつの JVM 言語 Frege と Eta について、モナドを利用した Java ライブラリ呼び出しの技法を解説します。

Published in: Technology

思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8

  1. 1. 思ったほど怖くない! Haskell on JVM 超入門 チェシャ猫 (@y_taka_23) JJUG CCC 2017 Spring (2017/05/20)
  2. 2. #jjug_ccc #ccc_l8
  3. 3. Haskell https://www.haskell.org #ccc_l8
  4. 4. 本日の目次 1. はじめまして Haskell 2. Haskell on JVM: Frege vs Eta a. モナドの内幕 b. Java 呼び出し、それぞれの戦略 3. 素敵な Haskell 生活の始め方 #ccc_l8
  5. 5. 1 はじめまして Haskell Haskell は何を目指して 作られた言語なのか?
  6. 6. Hello, Haskell! module Hello where greeting :: String -> String greeting name = “Hello, “ ++ name main :: IO () main = do putStrLn $ greeting “Haskell” putStrLn “Nice to meet you!” #ccc_l8
  7. 7. 「型」に注目してみる #ccc_l8
  8. 8. Haskell による Hello, World! module Hello where greeting :: String -> String greeting name = “Hello, “ ++ name main :: IO () main = do putStrLn $ greeting “Haskell” putStrLn “Nice to meet you!” “::” で型を記述する #ccc_l8
  9. 9. Haskell による Hello, World! module Hello where greeting :: String -> String greeting name = “Hello, “ ++ name main :: IO () main = do putStrLn $ greeting “Haskell” putStrLn “Nice to meet you!” String から String への関数 #ccc_l8
  10. 10. Haskell による Hello, World! module Hello where greeting :: String -> String greeting name = “Hello, “ ++ name main :: IO () main = do putStrLn $ greeting “Haskell” putStrLn “Nice to meet you!” Unit: Java の void 相当 #ccc_l8
  11. 11. Haskell による Hello, World! module Hello where greeting :: String -> String greeting name = “Hello, “ ++ name main :: IO () main = do putStrLn $ greeting “Haskell” putStrLn “Nice to meet you!” ??? #ccc_l8
  12. 12. 純粋性 Purity #ccc_l8
  13. 13. Haskell の「厄介な」ところ ▪ Java のような変数がない ▫ 変数に再代入できない ▫ Setter もなく、値は作成時から不変 ▪ 関数は引数以外の情報を使えない ▫ 引数が同じなら戻り値も常に同じ ▫ ただし完全に純粋な関数だけだと、意味のある プログラムが書けない #ccc_l8
  14. 14. Haskell による Hello, World! module Hello where greeting :: String -> String greeting name = “Hello, “ ++ name main :: IO () main = do putStrLn $ greeting “Haskell” putStrLn “Nice to meet you!” ??? #ccc_l8
  15. 15. Haskell による Hello, World! module Hello where greeting :: String -> String greeting name = “Hello, “ ++ name main :: IO () main = do putStrLn $ greeting “Haskell” putStrLn “Nice to meet you!” 「プログラム外への入出力を行う」型 #ccc_l8
  16. 16. Haskell の「頼もしい」ところ ▪ 他の言語では、副作用が予測不能 ▫ そもそも入出力は言語問わず隔離すべき ▫ 外界への依存は制御不能、テスタブルでない ▫ しかしそれを検知する手段がない ▪ Haskell では型として現れる ▫ 変なところで入出力を書こうとしても無理 ▫ 設計者の技量ではなく、コンパイラが保証 #ccc_l8
  17. 17. Section 1 のまとめ ▪ 純粋性が大きな特徴 ▫ あらゆるものが Immutable な世界 ▫ 関数の戻り値は引数のみから定まる ▪ 型が持つ情報量が多い ▫ 純粋な関数内では外界の情報が使えない ▫ 制御不可能な副作用に汚染されにくい #ccc_l8
  18. 18. 2 Haskell on JVM: Frege vs Eta Haskell 互換 JVM 言語 それぞれの特徴とは?
  19. 19. Frege http://frege-lang.org #ccc_l8
  20. 20. Frege はどんな言語なのか? ▪ Ingo Wechsung 氏が開発の中心 ▫ 2012 年 8 月に現在の v3 系がリリース ▪ Frege コンパイラ自身も Frege で実装 ▫ Haskell 2010 相当のコードに対応 ▫ コンパイラ拡張は対応の予定なし ▪ Java ソースコードを生成 ▫ Haskell の機能を Java で再現することに主眼 #ccc_l8
  21. 21. Eta http://eta-lang.org #ccc_l8
  22. 22. Eta はどんな言語なのか? ▪ TypeLead 社が開発の中心 ▫ 2017 年の 3 月に初リリース ▫ かなりのハイペースで進化中 ▪ Haskell のデファクトスタンダードな コンパイラ GHC をフォーク ▫ GHC 拡張が使用可能 ▪ 直接、クラスファイルを生成 #ccc_l8
  23. 23. JVM 言語としての視点から ▪ プラットフォームに依存しない ▫ 30 億のデバイスで動く ▪ Java のライブラリ呼び出しが可能 ▫ 既存の資産が再利用可能 ▪ しかし副作用に関する考え方が異なる ▫ Haskell (Frege, Eta): 純粋 ▫ Java: 非純粋、オブジェクトが状態を持つ #ccc_l8
  24. 24. Haskell の純粋性を保ったまま Java のライブラリを呼び出すには? #ccc_l8
  25. 25. モナド Monads #ccc_l8
  26. 26. モナド・コトハジメ ▪ モナドとは何か ▫ 式の「つなぎ方」を定義する仕組み ▫ Java でいえばインタフェースの一種 ▪ 数学・圏論を理解しないと使えない? ▫ 使うだけなら理論面は後回しで OK ▫ Step by Step で 理解しよう! #ccc_l8
  27. 27. (>>=) :: m a -> (a -> m b) -> m b #ccc_l8
  28. 28. なるほどわからん #ccc_l8
  29. 29. Step by Step で考えるモナド #ccc_l8
  30. 30. 「状態」のトイモデル ▪ スタックに対する操作を考える ▫ オブジェクトの内部状態に見立てる ▪ できるだけ単純化 ▫ 要素は Int 型のみ ▫ pop: スタック先頭の整数を取得 ▫ push x: スタックに整数 x を積む ▪ 純粋な Haskell で実装できるか? #ccc_l8
  31. 31. 最初に思いつく Haskell プログラム type Stack = [Int] pop :: Stack -> Int pop (x : xs) = x push :: Int -> Stack -> Stack push x xs = x : xs #ccc_l8
  32. 32. 最初に思いつく Haskell プログラム type Stack = [Int] pop :: Stack -> Int pop (x : xs) = x push :: Int -> Stack -> Stack push x xs = x : xs 型に別名(シノニム)をつけられる #ccc_l8
  33. 33. 最初に思いつく Haskell プログラム type Stack = [Int] pop :: Stack -> Int pop (x : xs) = x push :: Int -> Stack -> Stack push x xs = x : xs Int 型の連結リスト #ccc_l8
  34. 34. 最初に思いつく Haskell プログラム type Stack = [Int] pop :: Stack -> Int pop (x : xs) = x push :: Int -> Stack -> Stack push x xs = x : xs ”:” で連結リストの先頭と残りを連結 #ccc_l8
  35. 35. スタックに対する操作 ▪ 連続して操作したい ▫ 前の操作が次の操作の前提となる ▪ 操作した後の状態も明示的に返す ▫ 純粋性の枠内で可能 ▫ Stack -> (a, Stack) ▫ 戻り値の a は操作した結果得られる値の型、 Stack は変化後の状態 #ccc_l8
  36. 36. 変化後の状態も明示的に返す type Action a = Stack -> (a, Stack) pop :: Action Int pop (x : xs) = (x, xs) push :: Int -> Action () push x xs = ((), (x : xs)) #ccc_l8
  37. 37. 変化後の状態も明示的に返す type Action a = Stack -> (a, Stack) pop :: Action Int pop (x : xs) = (x, xs) push :: Int -> Action () push x xs = ((), (x : xs)) a 型の値を返すスタックの操作を表す型 #ccc_l8
  38. 38. 変化後の状態も明示的に返す type Action a = Stack -> (a, Stack) pop :: Action Int pop (x : xs) = (x, xs) push :: Int -> Action () push x xs = ((), (x : xs)) 変化後のスタック #ccc_l8
  39. 39. 変化後の状態も明示的に返す type Action a = Stack -> (a, Stack) pop :: Action Int pop (x : xs) = (x, xs) push :: Int -> Action () push x xs = ((), (x : xs)) Unit: Java の void 相当 #ccc_l8
  40. 40. 変化後の状態も明示的に返す addTop2 :: Action () addTop2 stack = let (x1, stack1) = pop stack (x2, stack2) = pop stack1 in push (x1 + x2) stack2 スタックのトップ 2 個を加算 #ccc_l8
  41. 41. 変化後の状態も明示的に返す addTop2 :: Action () addTop2 stack = let (x1, stack1) = pop stack (x2, stack2) = pop stack1 in push (x1 + x2) stack2 1 回目の操作の結果を保持 #ccc_l8
  42. 42. 変化後の状態も明示的に返す addTop2 :: Action () addTop2 stack = let (x1, stack1) = pop stack (x2, stack2) = pop stack1 in push (x1 + x2) stack2 1 回目の結果に対して 2 回目の操作 #ccc_l8
  43. 43. 変化後の状態も明示的に返す addTop2 :: Action () addTop2 stack = let (x1, stack1) = pop stack (x2, stack2) = pop stack1 in push (x1 + x2) stack2 2 回目の結果に対して 3 回目の操作 #ccc_l8
  44. 44. アクションの連結 ▪ 変化後の状態を合わせて渡す ▫ pop と push がつながるようになった ▫ つなげた結果も Action 型になっている ▪ もう少し一般的な形で書きたい ▫ 複数の Action 型の値をつなげたい ▫ つなげた結果も Action 型になるように #ccc_l8
  45. 45. アクションの連結 andThen :: Action a -> Action b -> Action b andThen act1 act2 stack = let (x1, stack1) = act1 stack (x2, stack2) = act2 stack1 in (x2, stack2) #ccc_l8
  46. 46. アクションの連結 andThen :: Action a -> Action b -> Action b andThen act1 act2 stack = let (x1, stack1) = act1 stack (x2, stack2) = act2 stack1 in (x2, stack2) act1 の結果を保持 #ccc_l8
  47. 47. アクションの連結 andThen :: Action a -> Action b -> Action b andThen act1 act2 stack = let (x1, stack1) = act1 stack (x2, stack2) = act2 stack1 in (x2, stack2) その結果に対して act2 を行う #ccc_l8
  48. 48. アクションの連結 andThen :: Action a -> Action b -> Action b andThen act1 act2 stack = let (x1, stack1) = act1 stack (x2, stack2) = act2 stack1 in (x2, stack2) x1 の情報が引き継がれない #ccc_l8
  49. 49. 値の情報を後で使えるようにする andThen :: Action a -> (a -> Action b) -> Action b andThen act1 factory stack = let (x1, stack1) = act1 stack (x2, stack2) = (factory x1) stack1 in (x2, stack2) #ccc_l8
  50. 50. 値の情報を後で使えるようにする andThen :: Action a -> (a -> Action b) -> Action b andThen act1 factory stack = let (x1, stack1) = act1 stack (x2, stack2) = (factory x1) stack1 in (x2, stack2) 第 2 引数をパラメータ化 #ccc_l8
  51. 51. 値の情報を後で使えるようにする andThen :: Action a -> (a -> Action b) -> Action b andThen act1 factory stack = let (x1, stack1) = act1 stack (x2, stack2) = (factory x1) stack1 in (x2, stack2) 1 回目の操作の結果を保持した後で #ccc_l8
  52. 52. 値の情報を後で使えるようにする andThen :: Action a -> (a -> Action b) -> Action b andThen act1 factory stack = let (x1, stack1) = act1 stack (x2, stack2) = (factory x1) stack1 in (x2, stack2) 1 回目の戻り値を使って 2 回目の操作を確定 #ccc_l8
  53. 53. 値の情報を後で使えるようにする andThen :: Action a -> (a -> Action b) -> Action b andThen act1 factory stack = let (x1, stack1) = act1 stack (x2, stack2) = (factory x1) stack1 in (x2, stack2) できた操作を 1 回目の結果に適用 #ccc_l8
  54. 54. アクションがうまく連結可能に! addTop2 :: Action () addTop2 = pop `andThen` (x1 -> pop `andThen` (x2 -> push (x1 + x2))) addTop4 :: Action () addTop4 = addTop2 `andThen` (sum1 -> addTop2 `andThen` (sum2 -> push (sum1 + sum2))) #ccc_l8
  55. 55. andThen :: Action a -> (a -> Action b) -> Action b #ccc_l8
  56. 56. (>>=) :: m a -> (a -> m b) -> m b #ccc_l8
  57. 57. モナドの正体見たり ▪ モナドはインタフェース的な存在 ▫ andThen に似た (>>=) が要求される ▫ 式の「つなぎ方」を規定する ▪ 情報として何を受け渡すかは実装による ▫ IO は RealWorld を「状態」とするモナド ▪ ただし記述がやや冗長 ▫ いわゆる「コールバック地獄」的な状況に #ccc_l8
  58. 58. do 記法 do Notation #ccc_l8
  59. 59. do 記法による「手続き型」スタイル addTop2 :: Action () addTop2 = pop >>= (x1 -> pop >>= (x2 -> push (x1 + x2))) #ccc_l8
  60. 60. do 記法による「手続き型」スタイル addTop2 :: Action () addTop2 = do x1 <- pop x2 <- pop push (x1 + x2) #ccc_l8
  61. 61. do 記法による「手続き型」スタイル addTop2 :: Action () addTop2 = do x1 <- pop x2 <- pop push (x1 + x2) あたかも代入っぽく書ける
  62. 62. モナドの正体見たり ▪ モナドはインタフェースの一種 ▫ andThen に似た (>>=) が要求される ▫ 式の「つなぎ方」を規定する ▪ 情報として何を受け渡すかは実装による ▫ IO は RealWorld を「状態」とするモナド ▪ do 記法によるシンタックスシュガー ▫ モナドにすると簡潔に書ける #ccc_l8
  63. 63. Frege の戦略 副作用をレベル分けする #ccc_l8
  64. 64. Java の非純粋性の 3 つのレベル ▪ Immutable なクラス ▫ 例 : BigInteger ▪ Mutable だが入出力を行わないクラス ▫ オブジェクトの内部に状態を蓄積 ▫ 例 : StringBuilder ▪ 入出力を行うクラス ▫ 例 : FileReader #ccc_l8
  65. 65. Frege における扱い ▪ Immutable なクラス ▫ そのまま Frege の型になる ▪ Mutable だが入出力を行わないクラス ▫ ??? ▪ 入出力を行うクラス ▫ ??? #ccc_l8
  66. 66. Immutable なクラス data JBigInt = pure native java.math.BigInteger where pure native new :: String -> JBigInt pure native add :: JBigInt -> JBigInt -> JBigInt add3 :: JBigInt -> JBigInt -> JBigInt -> JBigInt add3 n1 n2 n3 = (n1.add n2).add n3 #ccc_l8
  67. 67. Immutable なクラス data JBigInt = pure native java.math.BigInteger where pure native new :: String -> JBigInt pure native add :: JBigInt -> JBigInt -> JBigInt add3 :: JBigInt -> JBigInt -> JBigInt -> JBigInt add3 n1 n2 n3 = (n1.add n2).add n3 Frege 側で使う型名 #ccc_l8
  68. 68. Immutable なクラス data JBigInt = pure native java.math.BigInteger where pure native new :: String -> JBigInt pure native add :: JBigInt -> JBigInt -> JBigInt add3 :: JBigInt -> JBigInt -> JBigInt -> JBigInt add3 n1 n2 n3 = (n1.add n2).add n3 Immutable なら pure native #ccc_l8
  69. 69. Immutable なクラス data JBigInt = pure native java.math.BigInteger where pure native new :: String -> JBigInt pure native add :: JBigInt -> JBigInt -> JBigInt add3 :: JBigInt -> JBigInt -> JBigInt -> JBigInt add3 n1 n2 n3 = (n1.add n2).add n3 new と名付けた関数がコンストラクタに #ccc_l8
  70. 70. Immutable なクラス data JBigInt = pure native java.math.BigInteger where pure native new :: String -> JBigInt pure native add :: JBigInt -> JBigInt -> JBigInt add3 :: JBigInt -> JBigInt -> JBigInt -> JBigInt add3 n1 n2 n3 = (n1.add n2).add n3 Java の BigInteger#add #ccc_l8
  71. 71. Immutable なクラス data JBigInt = pure native java.math.BigInteger where pure native new :: String -> JBigInt pure native add :: JBigInt -> JBigInt -> JBigInt add3 :: JBigInt -> JBigInt -> JBigInt -> JBigInt add3 n1 n2 n3 = (n1.add n2).add n3 ドットでメソッド呼び出し #ccc_l8
  72. 72. Frege における扱い ▪ Immutable なクラス ▫ そのまま Frege の型になる ▪ Mutable だが入出力を行わないクラス ▫ ??? ▪ 入出力を行うクラス ▫ IO モナドになる #ccc_l8
  73. 73. 入出力を伴うクラス data JFReader = mutable native java.io.FileReader where native new :: String -> IO JFReader native read :: JFReader -> IO Int readOneFrom :: String -> IO Int readOneFrom filename = do fr <- JFReader.new filename fr.read #ccc_l8
  74. 74. 入出力を伴うクラス data JFReader = mutable native java.io.FileReader where native new :: String -> IO JFReader native read :: JFReader -> IO Int readOneFrom :: String -> IO Int readOneFrom filename = do fr <- JFReader.new filename fr.read IO 用のクラスは mutable native #ccc_l8
  75. 75. 入出力を伴うクラス data JFReader = mutable native java.io.FileReader where native new :: String -> IO JFReader native read :: JFReader -> IO Int readOneFrom :: String -> IO Int readOneFrom filename = do fr <- JFReader.new filename fr.read 各メソッドは IO モナドに #ccc_l8
  76. 76. Frege における扱い ▪ Immutable なクラス ▫ そのまま Frege の型になる ▪ Mutable だが入出力を行わないクラス ▫ (ここがJVM 言語としての事情) ▪ 入出力を行うクラス ▫ IO モナドになる #ccc_l8
  77. 77. 「表向き純粋」なメソッド public String greeting(String name) { StringBuilder sb = new StringBuilder(“Hello, “); sb.append(name); return sb.toString(); } #ccc_l8
  78. 78. 「表向き純粋」なメソッド public String greeting(String name) { StringBuilder sb = new StringBuilder(“Hello, “); sb.append(name); return sb.toString(); } インスタンスの破壊的更新 #ccc_l8
  79. 79. 「表向き純粋」なメソッド public String greeting(String name) { StringBuilder sb = new StringBuilder(“Hello, “); sb.append(name); return sb.toString(); } しかし戻り値は引数のみから定まる #ccc_l8
  80. 80. STモナドを使おう! #ccc_l8
  81. 81. ST (State Transformer) モナド ▪ 破壊的更新を局所化 ▫ 実際にメモリ上の値を書き換える ▪ ST s TypeName ▫ s は「観測不可能」な内部状態 ▫ s は常に型変数で、具体化できない ▪ 純粋な値を取り出すことができる ▫ IO モナドでは値の取り出しは不可能 #ccc_l8
  82. 82. Mutable なクラス data JBuilder = native java.lang.StringBuilder where native new :: String -> ST s (Mutable s JBuilder) native append :: Mutable s JBuilder -> String -> ST s (Mutable s JBuilder) #ccc_l8
  83. 83. Mutable なクラス data JBuilder = native java.lang.StringBuilder where native new :: String -> ST s (Mutable s JBuilder) native append :: Mutable s JBuilder -> String -> ST s (Mutable s JBuilder) 入出力なしなら native のみ #ccc_l8
  84. 84. Mutable なクラス data JBuilder = native java.lang.StringBuilder where native new :: String -> ST s (Mutable s JBuilder) native append :: Mutable s JBuilder -> String -> ST s (Mutable s JBuilder) 外部から「観測不可能」な内部状態 #ccc_l8
  85. 85. Mutable なクラス data JBuilder = native java.lang.StringBuilder where native new :: String -> ST s (Mutable s JBuilder) native append :: Mutable s JBuilder -> String -> ST s (Mutable s JBuilder) Mutable でラップ #ccc_l8
  86. 86. Mutable なクラス data JBuilder = native java.lang.StringBuilder where native new :: String -> ST s (Mutable s JBuilder) native append :: Mutable s JBuilder -> String -> ST s (Mutable s JBuilder) 戻り値は ST モナド #ccc_l8
  87. 87. Mutable なクラス greeting :: String -> ST s String greeting name = do sb <- JBuilder.new “Hello, ” sb.append name sb.toString pureGreeting :: String -> String pureGreeting name = (greeting name).run #ccc_l8
  88. 88. Mutable なクラス greeting :: String -> ST s String greeting name = do sb <- JBuilder.new “Hello, ” sb.append name sb.toString pureGreeting :: String -> String pureGreeting name = (greeting name).run ST モナドとして使用 #ccc_l8
  89. 89. Mutable なクラス greeting :: String -> ST s String greeting name = do sb <- JBuilder.new “Hello, ” sb.append name sb.toString pureGreeting :: String -> String pureGreeting name = (greeting name).run run で純粋な値を取り出す #ccc_l8
  90. 90. Mutable なクラス greeting :: String -> ST s String greeting name = do sb <- JBuilder.new “Hello, ” sb.append name sb.toString pureGreeting :: String -> String pureGreeting name = (greeting name).run 外から見ると純粋な関数 #ccc_l8
  91. 91. Frege における扱い ▪ Immutable なクラス ▫ そのまま Frege の型になる ▪ Mutable だが入出力を行わないクラス ▫ ST モナドになる ▪ 入出力を行うクラス ▫ IO モナドになる #ccc_l8
  92. 92. Eta の戦略 メソッドレシーバを状態だと考える #ccc_l8
  93. 93. Java モナド ▪ Eta 独自の仕組み ▫ フレームワークとしてモナドを利用 ▪ Java a b ▫ a はレシーバ、b は戻り値の型 ▫ a 型の値に対してメソッドの並びを呼び出すと、 結果として b 型の値が得られる ▫ クラスの数だけ別種のモナドができる #ccc_l8
  94. 94. Java のインポート data {-# CLASS “java.io.File” #-} File = File (Object# File) deriving Class foreign import java unsafe canExecute :: Java File Bool foreign import java unsafe “@new” newFile :: String -> Java a File #ccc_l8
  95. 95. Java のインポート data {-# CLASS “java.io.File” #-} File = File (Object# File) deriving Class foreign import java unsafe canExecute :: Java File Bool foreign import java unsafe “@new” newFile :: String -> Java a File 書式はどのクラスも同じ #ccc_l8
  96. 96. Java のインポート data {-# CLASS “java.io.File” #-} File = File (Object# File) deriving Class foreign import java unsafe canExecute :: Java File Bool foreign import java unsafe “@new” newFile :: String -> Java a File レシーバが File 型、戻り値が Bool 型 #ccc_l8
  97. 97. Java のインポート data {-# CLASS “java.io.File” #-} File = File (Object# File) deriving Class foreign import java unsafe canExecute :: Java File Bool foreign import java unsafe “@new” newFile :: String -> Java a File コンストラクタには “@new” がつく #ccc_l8
  98. 98. 複数のモナドを組み合わせる! #ccc_l8
  99. 99. Java アクションをつなぐ関数 ▪ java :: Java a b -> IO b ▫ Java モナドを IO モナドの中に埋め込む ▪ Io :: IO b -> Java a b ▫ IO モナドを Java モナドの中に埋め込む #ccc_l8
  100. 100. Java アクションをつなぐ関数 ▪ (>-) :: Java a b -> Java b c -> -> Java a c ▫ Java モナド同士をつなぐ ▫ 前半のアクションの戻り値が、後半のアクションの レシーバになる #ccc_l8
  101. 101. 複数のモナドを組み立てる main :: IO () main = java $ do isExec <- newFile “./dir/app.sh” >- canExecute io $ putStrLn “Checking” if isExec then io $ putStrLn “It’s OK!” else io $ putStrLn “Too Bad...” #ccc_l8
  102. 102. 複数のモナドを組み立てる main :: IO () main = java $ do isExec <- newFile “./dir/app.sh” >- canExecute io $ putStrLn “Checking” if isExec then io $ putStrLn “It’s OK!” else io $ putStrLn “Too Bad...” 全体としては IO モナド #ccc_l8
  103. 103. 複数のモナドを組み立てる main :: IO () main = java $ do isExec <- newFile “./dir/app.sh” >- canExecute io $ putStrLn “Checking” if isExec then io $ putStrLn “It’s OK!” else io $ putStrLn “Too Bad...” そのすぐ内側は Java モナド #ccc_l8
  104. 104. 複数のモナドを組み立てる main :: IO () main = java $ do isExec <- newFile “./dir/app.sh” >- canExecute io $ putStrLn “Checking” if isExec then io $ putStrLn “It’s OK!” else io $ putStrLn “Too Bad...” Java a File 型の Java アクション #ccc_l8
  105. 105. 複数のモナドを組み立てる main :: IO () main = java $ do isExec <- newFile “./dir/app.sh” >- canExecute io $ putStrLn “Checking” if isExec then io $ putStrLn “It’s OK!” else io $ putStrLn “Too Bad...” Java File Bool 型の Java アクション #ccc_l8
  106. 106. 複数のモナドを組み立てる main :: IO () main = java $ do isExec <- newFile “./dir/app.sh” >- canExecute io $ putStrLn “Checking” if isExec then io $ putStrLn “It’s OK!” else io $ putStrLn “Too Bad...” 戻り値だった File 型の値が次のレシーバに #ccc_l8
  107. 107. 複数のモナドを組み立てる main :: IO () main = java $ do isExec <- newFile “./dir/app.sh” >- canExecute io $ putStrLn “Checking” if isExec then io $ putStrLn “It’s OK!” else io $ putStrLn “Too Bad...” IO モナドが #ccc_l8
  108. 108. 複数のモナドを組み立てる main :: IO () main = java $ do isExec <- newFile “./dir/app.sh” >- canExecute io $ putStrLn “Checking” if isExec then io $ putStrLn “It’s OK!” else io $ putStrLn “Too Bad...” Java モナドに埋め込まれる #ccc_l8
  109. 109. Section 2 のまとめ ▪ モナドはインタフェース的な存在 ▫ 純粋性を保ったまま状態を表現 ▫ do 記法による言語自体のサポート ▪ Frege: pure, ST, IO によるモデル化 ▫ 副作用の「強さ」でレベル分け ▪ Eta: Java モナドによるモデル化 ▫ IO も含め、複数種類のモナドを組み合わせる #ccc_l8
  110. 110. 3 素敵な Haskell 生活の始め方 最初の一歩を踏み出すための ツール・教材たち
  111. 111. 結局、Frege と Eta なら どっちがオススメ? #ccc_l8
  112. 112. 両言語のターゲット層 ▪ Frege: Javaer のための Haskell ▫ あくまでも標準 Haskell 互換機能のみ ▫ Java 呼び出しが比較的シンプル ▪ Eta: Haskeller 向けの JVM 言語 ▫ GHC 拡張が使用可能 ▫ Java の呼び出しがやや複雑 ■ モナドの組み合わせが必須 #ccc_l8
  113. 113. ビルドまでのセットアップ ▪ Frege ▫ 既存の Java ビルドツールを使用 ■ Gradle, Maven, sbt, leiningen etc ▫ コンパイラはプラグインとして提供 ▪ Eta ▫ 専用ツール Etlas を使用 ▫ コンパイラ自体のコンパイルからスタート #ccc_l8
  114. 114. 本日のオススメ http://frege-lang.org #ccc_l8
  115. 115. オススメ参考書、その一 #ccc_l8
  116. 116. すごい Haskell たのしく学ぼう! ▪ Haskell 入門書の定番 ▫ Web 版は無料公開 ▫ モナドの説明がわかりやすい ▪ 『すごい Frege』もある ▫ Web 版の全サンプルコードを移植 ▫ https://github.com/y-taka-23/learn-you- a-frege #ccc_l8
  117. 117. オススメ参考書、その二 #ccc_l8
  118. 118. Frege Goodness ▪ Javaer 向けの短い記事集 ▫ GitBook で無料公開 ▫ https://www.gitbook.com/book/dierk/freg egoodness ▪ 日本語版あり ▫ https://www.gitbook.com/book/y-taka-23/ frege-goodness-jp #ccc_l8
  119. 119. 日本 Haskell ユーザ会 ▪ 通称 Haskell-jp ▫ 2017 年 3 月に発足したて ▪ もくもく会 ▫ 月 1 回ペースで開催中 @ 東銀座 ▫ 初心者歓迎、一見さん歓迎 ▪ Slack ▫ https://haskell-jp.slack.com #ccc_l8
  120. 120. Section 3 のまとめ ▪ はじめての人は Frege から ▫ Frege: Javaer のための Haskell ▫ Eta: Haskeller 向けの JVM 言語 ▪ いつものツールでビルド ▪ 勉強の道標はいろいろ ▫ Frege 対応参考書あります ▫ 困ったら Haskell-jp へ #ccc_l8
  121. 121. 4 まとめ 結局、この 45 分間で 我々は何を得たのか?
  122. 122. 本日のまとめ ▪ 純粋言語 Haskell ▫ 副作用を予測可能にする型システム ▪ 巧みな Java 呼び出し ▫ Frege: pure, ST, IO によるモデル化 ▫ Eta: Java モナドによるモデル化 ▪ まず Frege から始めてみよう! #ccc_l8
  123. 123. Happy Haskelling! Presented by チェシャ猫 (@y_taka_23) #ccc_l8
  124. 124. CREDITS Special thanks to all the people who made and released these awesome resources for free: ▪ Presentation template by SlidesCarnival ▪ Photographs by Unsplash

×