Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

19,113 views

Published on

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

関連ブログ記事 : http://ccvanishing.hateblo.jp/entry/2017/05/21/150903

Published in: Technology
  • Be the first to comment

思ったほど怖くない! 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

×