思ったほど怖くない!
Haskell on JVM
超入門
チェシャ猫 (@y_taka_23)
JJUG CCC 2017 Spring (2017/05/20)
#jjug_ccc
#ccc_l8
Haskell
https://www.haskell.org
#ccc_l8
本日の目次
1. はじめまして Haskell
2. Haskell on JVM: Frege vs Eta
a. モナドの内幕
b. Java 呼び出し、それぞれの戦略
3. 素敵な Haskell 生活の始め方
#ccc_l8
1
はじめまして Haskell
Haskell は何を目指して
作られた言語なのか?
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
「型」に注目してみる
#ccc_l8
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
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
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
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
純粋性
Purity
#ccc_l8
Haskell の「厄介な」ところ
▪ Java のような変数がない
▫ 変数に再代入できない
▫ Setter もなく、値は作成時から不変
▪ 関数は引数以外の情報を使えない
▫ 引数が同じなら戻り値も常に同じ
▫ ただし完全に純粋な関数だけだと、意味のある
プログラムが書けない
#ccc_l8
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
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
Haskell の「頼もしい」ところ
▪ 他の言語では、副作用が予測不能
▫ そもそも入出力は言語問わず隔離すべき
▫ 外界への依存は制御不能、テスタブルでない
▫ しかしそれを検知する手段がない
▪ Haskell では型として現れる
▫ 変なところで入出力を書こうとしても無理
▫ 設計者の技量ではなく、コンパイラが保証
#ccc_l8
Section 1 のまとめ
▪ 純粋性が大きな特徴
▫ あらゆるものが Immutable な世界
▫ 関数の戻り値は引数のみから定まる
▪ 型が持つ情報量が多い
▫ 純粋な関数内では外界の情報が使えない
▫ 制御不可能な副作用に汚染されにくい
#ccc_l8
2
Haskell on JVM:
Frege vs Eta
Haskell 互換 JVM 言語
それぞれの特徴とは?
Frege
http://frege-lang.org
#ccc_l8
Frege はどんな言語なのか?
▪ Ingo Wechsung 氏が開発の中心
▫ 2012 年 8 月に現在の v3 系がリリース
▪ Frege コンパイラ自身も Frege で実装
▫ Haskell 2010 相当のコードに対応
▫ コンパイラ拡張は対応の予定なし
▪ Java ソースコードを生成
▫ Haskell の機能を Java で再現することに主眼
#ccc_l8
Eta
http://eta-lang.org
#ccc_l8
Eta はどんな言語なのか?
▪ TypeLead 社が開発の中心
▫ 2017 年の 3 月に初リリース
▫ かなりのハイペースで進化中
▪ Haskell のデファクトスタンダードな
コンパイラ GHC をフォーク
▫ GHC 拡張が使用可能
▪ 直接、クラスファイルを生成
#ccc_l8
JVM 言語としての視点から
▪ プラットフォームに依存しない
▫ 30 億のデバイスで動く
▪ Java のライブラリ呼び出しが可能
▫ 既存の資産が再利用可能
▪ しかし副作用に関する考え方が異なる
▫ Haskell (Frege, Eta): 純粋
▫ Java: 非純粋、オブジェクトが状態を持つ
#ccc_l8
Haskell の純粋性を保ったまま
Java のライブラリを呼び出すには?
#ccc_l8
モナド
Monads
#ccc_l8
モナド・コトハジメ
▪ モナドとは何か
▫ 式の「つなぎ方」を定義する仕組み
▫ Java でいえばインタフェースの一種
▪ 数学・圏論を理解しないと使えない?
▫ 使うだけなら理論面は後回しで OK
▫ Step by Step で 理解しよう!
#ccc_l8
(>>=) :: m a -> (a -> m b) -> m b
#ccc_l8
なるほどわからん
#ccc_l8
Step by Step で考えるモナド
#ccc_l8
「状態」のトイモデル
▪ スタックに対する操作を考える
▫ オブジェクトの内部状態に見立てる
▪ できるだけ単純化
▫ 要素は Int 型のみ
▫ pop: スタック先頭の整数を取得
▫ push x: スタックに整数 x を積む
▪ 純粋な Haskell で実装できるか?
#ccc_l8
最初に思いつく Haskell プログラム
type Stack = [Int]
pop :: Stack -> Int
pop (x : xs) = x
push :: Int -> Stack -> Stack
push x xs = x : xs
#ccc_l8
最初に思いつく Haskell プログラム
type Stack = [Int]
pop :: Stack -> Int
pop (x : xs) = x
push :: Int -> Stack -> Stack
push x xs = x : xs
型に別名(シノニム)をつけられる
#ccc_l8
最初に思いつく Haskell プログラム
type Stack = [Int]
pop :: Stack -> Int
pop (x : xs) = x
push :: Int -> Stack -> Stack
push x xs = x : xs
Int 型の連結リスト
#ccc_l8
最初に思いつく Haskell プログラム
type Stack = [Int]
pop :: Stack -> Int
pop (x : xs) = x
push :: Int -> Stack -> Stack
push x xs = x : xs
”:” で連結リストの先頭と残りを連結
#ccc_l8
スタックに対する操作
▪ 連続して操作したい
▫ 前の操作が次の操作の前提となる
▪ 操作した後の状態も明示的に返す
▫ 純粋性の枠内で可能
▫ Stack -> (a, Stack)
▫ 戻り値の a は操作した結果得られる値の型、
Stack は変化後の状態
#ccc_l8
変化後の状態も明示的に返す
type Action a = Stack -> (a, Stack)
pop :: Action Int
pop (x : xs) = (x, xs)
push :: Int -> Action ()
push x xs = ((), (x : xs))
#ccc_l8
変化後の状態も明示的に返す
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
変化後の状態も明示的に返す
type Action a = Stack -> (a, Stack)
pop :: Action Int
pop (x : xs) = (x, xs)
push :: Int -> Action ()
push x xs = ((), (x : xs))
変化後のスタック
#ccc_l8
変化後の状態も明示的に返す
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
変化後の状態も明示的に返す
addTop2 :: Action ()
addTop2 stack =
let (x1, stack1) = pop stack
(x2, stack2) = pop stack1
in push (x1 + x2) stack2
スタックのトップ 2 個を加算
#ccc_l8
変化後の状態も明示的に返す
addTop2 :: Action ()
addTop2 stack =
let (x1, stack1) = pop stack
(x2, stack2) = pop stack1
in push (x1 + x2) stack2
1 回目の操作の結果を保持
#ccc_l8
変化後の状態も明示的に返す
addTop2 :: Action ()
addTop2 stack =
let (x1, stack1) = pop stack
(x2, stack2) = pop stack1
in push (x1 + x2) stack2
1 回目の結果に対して 2 回目の操作
#ccc_l8
変化後の状態も明示的に返す
addTop2 :: Action ()
addTop2 stack =
let (x1, stack1) = pop stack
(x2, stack2) = pop stack1
in push (x1 + x2) stack2
2 回目の結果に対して 3 回目の操作
#ccc_l8
アクションの連結
▪ 変化後の状態を合わせて渡す
▫ pop と push がつながるようになった
▫ つなげた結果も Action 型になっている
▪ もう少し一般的な形で書きたい
▫ 複数の Action 型の値をつなげたい
▫ つなげた結果も Action 型になるように
#ccc_l8
アクションの連結
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
アクションの連結
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
アクションの連結
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
アクションの連結
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
値の情報を後で使えるようにする
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
値の情報を後で使えるようにする
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
値の情報を後で使えるようにする
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
値の情報を後で使えるようにする
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
値の情報を後で使えるようにする
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
アクションがうまく連結可能に!
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
andThen :: Action a -> (a -> Action b)
-> Action b
#ccc_l8
(>>=) :: m a -> (a -> m b) -> m b
#ccc_l8
モナドの正体見たり
▪ モナドはインタフェース的な存在
▫ andThen に似た (>>=) が要求される
▫ 式の「つなぎ方」を規定する
▪ 情報として何を受け渡すかは実装による
▫ IO は RealWorld を「状態」とするモナド
▪ ただし記述がやや冗長
▫ いわゆる「コールバック地獄」的な状況に
#ccc_l8
do 記法
do Notation
#ccc_l8
do 記法による「手続き型」スタイル
addTop2 :: Action ()
addTop2 =
pop >>= (x1 ->
pop >>= (x2 ->
push (x1 + x2)))
#ccc_l8
do 記法による「手続き型」スタイル
addTop2 :: Action ()
addTop2 = do
x1 <- pop
x2 <- pop
push (x1 + x2)
#ccc_l8
do 記法による「手続き型」スタイル
addTop2 :: Action ()
addTop2 = do
x1 <- pop
x2 <- pop
push (x1 + x2)
あたかも代入っぽく書ける
モナドの正体見たり
▪ モナドはインタフェースの一種
▫ andThen に似た (>>=) が要求される
▫ 式の「つなぎ方」を規定する
▪ 情報として何を受け渡すかは実装による
▫ IO は RealWorld を「状態」とするモナド
▪ do 記法によるシンタックスシュガー
▫ モナドにすると簡潔に書ける
#ccc_l8
Frege の戦略
副作用をレベル分けする
#ccc_l8
Java の非純粋性の 3 つのレベル
▪ Immutable なクラス
▫ 例 : BigInteger
▪ Mutable だが入出力を行わないクラス
▫ オブジェクトの内部に状態を蓄積
▫ 例 : StringBuilder
▪ 入出力を行うクラス
▫ 例 : FileReader
#ccc_l8
Frege における扱い
▪ Immutable なクラス
▫ そのまま Frege の型になる
▪ Mutable だが入出力を行わないクラス
▫ ???
▪ 入出力を行うクラス
▫ ???
#ccc_l8
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
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
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
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
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
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
Frege における扱い
▪ Immutable なクラス
▫ そのまま Frege の型になる
▪ Mutable だが入出力を行わないクラス
▫ ???
▪ 入出力を行うクラス
▫ IO モナドになる
#ccc_l8
入出力を伴うクラス
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
入出力を伴うクラス
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
入出力を伴うクラス
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
Frege における扱い
▪ Immutable なクラス
▫ そのまま Frege の型になる
▪ Mutable だが入出力を行わないクラス
▫ (ここがJVM 言語としての事情)
▪ 入出力を行うクラス
▫ IO モナドになる
#ccc_l8
「表向き純粋」なメソッド
public String greeting(String name) {
StringBuilder sb =
new StringBuilder(“Hello, “);
sb.append(name);
return sb.toString();
}
#ccc_l8
「表向き純粋」なメソッド
public String greeting(String name) {
StringBuilder sb =
new StringBuilder(“Hello, “);
sb.append(name);
return sb.toString();
}
インスタンスの破壊的更新
#ccc_l8
「表向き純粋」なメソッド
public String greeting(String name) {
StringBuilder sb =
new StringBuilder(“Hello, “);
sb.append(name);
return sb.toString();
}
しかし戻り値は引数のみから定まる
#ccc_l8
STモナドを使おう!
#ccc_l8
ST (State Transformer) モナド
▪ 破壊的更新を局所化
▫ 実際にメモリ上の値を書き換える
▪ ST s TypeName
▫ s は「観測不可能」な内部状態
▫ s は常に型変数で、具体化できない
▪ 純粋な値を取り出すことができる
▫ IO モナドでは値の取り出しは不可能
#ccc_l8
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
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
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
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
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
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
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
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
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
Frege における扱い
▪ Immutable なクラス
▫ そのまま Frege の型になる
▪ Mutable だが入出力を行わないクラス
▫ ST モナドになる
▪ 入出力を行うクラス
▫ IO モナドになる
#ccc_l8
Eta の戦略
メソッドレシーバを状態だと考える
#ccc_l8
Java モナド
▪ Eta 独自の仕組み
▫ フレームワークとしてモナドを利用
▪ Java a b
▫ a はレシーバ、b は戻り値の型
▫ a 型の値に対してメソッドの並びを呼び出すと、
結果として b 型の値が得られる
▫ クラスの数だけ別種のモナドができる
#ccc_l8
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
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
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
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
複数のモナドを組み合わせる!
#ccc_l8
Java アクションをつなぐ関数
▪ java :: Java a b -> IO b
▫ Java モナドを IO モナドの中に埋め込む
▪ Io :: IO b -> Java a b
▫ IO モナドを Java モナドの中に埋め込む
#ccc_l8
Java アクションをつなぐ関数
▪ (>-) :: Java a b -> Java b c ->
-> Java a c
▫ Java モナド同士をつなぐ
▫ 前半のアクションの戻り値が、後半のアクションの
レシーバになる
#ccc_l8
複数のモナドを組み立てる
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
複数のモナドを組み立てる
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
複数のモナドを組み立てる
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
複数のモナドを組み立てる
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
複数のモナドを組み立てる
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
複数のモナドを組み立てる
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
複数のモナドを組み立てる
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
複数のモナドを組み立てる
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
Section 2 のまとめ
▪ モナドはインタフェース的な存在
▫ 純粋性を保ったまま状態を表現
▫ do 記法による言語自体のサポート
▪ Frege: pure, ST, IO によるモデル化
▫ 副作用の「強さ」でレベル分け
▪ Eta: Java モナドによるモデル化
▫ IO も含め、複数種類のモナドを組み合わせる
#ccc_l8
3
素敵な Haskell 生活の始め方
最初の一歩を踏み出すための
ツール・教材たち
結局、Frege と Eta なら
どっちがオススメ?
#ccc_l8
両言語のターゲット層
▪ Frege: Javaer のための Haskell
▫ あくまでも標準 Haskell 互換機能のみ
▫ Java 呼び出しが比較的シンプル
▪ Eta: Haskeller 向けの JVM 言語
▫ GHC 拡張が使用可能
▫ Java の呼び出しがやや複雑
■ モナドの組み合わせが必須
#ccc_l8
ビルドまでのセットアップ
▪ Frege
▫ 既存の Java ビルドツールを使用
■ Gradle, Maven, sbt, leiningen etc
▫ コンパイラはプラグインとして提供
▪ Eta
▫ 専用ツール Etlas を使用
▫ コンパイラ自体のコンパイルからスタート
#ccc_l8
本日のオススメ
http://frege-lang.org
#ccc_l8
オススメ参考書、その一
#ccc_l8
すごい Haskell たのしく学ぼう!
▪ Haskell 入門書の定番
▫ Web 版は無料公開
▫ モナドの説明がわかりやすい
▪ 『すごい Frege』もある
▫ Web 版の全サンプルコードを移植
▫ https://github.com/y-taka-23/learn-you-
a-frege
#ccc_l8
オススメ参考書、その二
#ccc_l8
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
日本 Haskell ユーザ会
▪ 通称 Haskell-jp
▫ 2017 年 3 月に発足したて
▪ もくもく会
▫ 月 1 回ペースで開催中 @ 東銀座
▫ 初心者歓迎、一見さん歓迎
▪ Slack
▫ https://haskell-jp.slack.com
#ccc_l8
Section 3 のまとめ
▪ はじめての人は Frege から
▫ Frege: Javaer のための Haskell
▫ Eta: Haskeller 向けの JVM 言語
▪ いつものツールでビルド
▪ 勉強の道標はいろいろ
▫ Frege 対応参考書あります
▫ 困ったら Haskell-jp へ
#ccc_l8
4
まとめ
結局、この 45 分間で
我々は何を得たのか?
本日のまとめ
▪ 純粋言語 Haskell
▫ 副作用を予測可能にする型システム
▪ 巧みな Java 呼び出し
▫ Frege: pure, ST, IO によるモデル化
▫ Eta: Java モナドによるモデル化
▪ まず Frege から始めてみよう!
#ccc_l8
Happy Haskelling!
Presented by
チェシャ猫 (@y_taka_23)
#ccc_l8
CREDITS
Special thanks to all the people who made and released
these awesome resources for free:
▪ Presentation template by SlidesCarnival
▪ Photographs by Unsplash

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