SlideShare ist ein Scribd-Unternehmen logo
1 von 40
Downloaden Sie, um offline zu lesen
ScalaプログラマのためのHaskell入門 
竹辺 靖昭
●GREEでHaskellプログラマをやっています http://labs.gree.jp/blog/2013/12/9201/ 
●最近Scalaでコードを書きはじめました 
自己紹介
●「Haskellは再代入ができないから参照透過性が確保される」 
●「Scalaを使っているけど、もっと関数的な書き方を身につけたいか らHaskellも勉強してみよう」 
●Haskellでも手続き的に書けます! 
Haskellに関するよくある誤解
●Haskellで手続き的に書くなんて邪道ではないか? 
●Haskellの設計者 Simon Peyton Jones の言 
●Tackling the Awkward Squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell 
●Haskell is the world’s finest imperative programming language 「Haskellは世界最高の手続き型プログラミング言語です」 
●設計者が手続き型言語と言っているので手続き的に書いて全く問題あ りません 
Haskellに関するよくある誤解
●環境構築 
●Haskell Platformのインストール 
●Scala v.s. Haskell 
●Haskellコードの読み方 
●対応表 
●Haskellで書く手続き型プログラム 
●変数(MVar, STM) 
●配列(IOArray) 
●シェルスクリプト(Shelly) 
目次
●見た目はとてもかっこいい 
Haskellコードの読み方
●見た目はとてもかっこいい、が読み方がよくわからない 
Haskellコードの読み方
●関数定義 
●Haskellでは型を別の行に書く(省略も可) 
●引数に括弧がいらない 
Haskellコードの読み方 (続き) 
Scala 
Haskell 
def fun(x: Int, y: Int): Int = x + y 
fun :: Int -> Int -> Int fun x y = x + y
●ラムダ式 
●引数を使わない時は _ -> ... のように書く 
Haskellコードの読み方 (続き) 
Scala 
Haskell 
(x: Int) => x + 1 
x -> x + 1 
(x: Int, y: Int) => x + y 
x y -> x + y
●関数の後に引数を並べると関数適用 
Haskellコードの読み方 
Scala 
Haskell 
foo(1, 2) 
foo 1 2 
bar(2, x + 1) 
bar 2 (x + 1)
●引数を一部書かないと部分適用 
●最後からしか省略できないのでHaskellでは引数の順番が重要 
●flip関数: flip f = x y -> f y x 
●x -> foo x 2 は (flip f) 2 と書ける 
Haskellコードの読み方 (続き) 
Scala 
Haskell 
foo(1, (_: Int)) 
foo 1 
bar((_: Int), (_: Int)) 
bar
●演算子の場合 
●括弧で囲むとinfixをprefixにできる 
●例: x + 1 は (x +) 1 と同じ 
●逆に普通の関数をバッククオートで囲むとinfixになる 
●例 isPrefixOf "hoge" str は "hoge" `isPrefixOf` str と同じ 
Haskellコードの読み方 (続き) 
Scala 
Haskell 
1 + (_: Int) 
(1 +) 
(_: Int) + (_: Int) 
(+)
●$演算子 
●後ろの式を括弧で囲んだのと同じ 
●baz $ foo $ 1 + 2 $ 3 + 4 は baz (foo (1 + 2) (3 + 4)) と同じ 
●変数名を装飾するものではない 
●かなり多用される 
Haskellコードの読み方 (続き)
●関数合成 
●関数合成もかなり多用される 
●ポイントフリースタイル 
●x -> f (g (h x)) は f . g . h と同じ 
●例: filter (not . even) [1, 2, 3] 
●'.' を使っているがメンバーやメソッドの参照ではない 
Haskellコードの読み方 (続き) 
Scala 
Haskell 
f compose g 
f . g
●関数合成の応用 
●(.) : 関数合成の前置記法 
●(.) f g は f . g と同じ 
●(f .) : 関数合成の部分適用 
Haskellコードの読み方 (続き)
●文字列から最初の単語を切り出す関数 takeWord = takeWhile (not . (flip elem) [' ', 'n', 't']) 
●takeWhile関数 
●takeWhile (文字からBoolの関数) (文字列) 文字列の文字が条件をみたす限り文字を取り続ける 
●elem関数 
●elem (文字) (文字のリスト) 文字が文字のリストに含まれていればTrue 
Haskellコードの読み方 (続き)
●"ポインティ"スタイル takeWord str = takeWhile (c -> not (elem c [' ', 'n', 't'])) str 
●最後のstrは同じなのでなくてもよい takeWord = takeWhile (c -> not (elem c [' ', 'n', 't'])) 
●cを消したいのでflipを使う takeWord = takeWhile (c -> not ((flip elem) [' ', 'n', 't'] c)) 
●x -> g (f x) は g . f と同じ takeWord = takeWhile (not . (flip elem) [' ', 'n', 't']) 
Haskellコードの読み方 (続き)
●対応表(モナド/逐次処理) 
●Haskellには文はない 
●文に相当する処理はモナドを使って書く 
Scala v.s. Haskell 
Scala 
Haskell 
文 
N/A 
for 
do 
map 
fmap 
flatMap 
>>= (bind) 
N/A 
>> (then)
●モナドといってもdo記法の中では「文」を並べているように書けるの であまり違和感はない 
●例:main :: IO () main = do let prompt = "Input your name: " let message = "Hello, " putStr prompt name <- getLine putStrLn $ message ++ name 
●実際にはdo記法は >> と >>= を使った式に展開できる (cf. Real World Haskell 14.11) 
Scala v.s. Haskell
●対応表(制御構造) 
●Haskellのreturnは制御構造ではない 
●関数の途中で戻ることはできない 
Scala v.s. Haskell 
Scala 
Haskell 
if 
if 
match 
case 
for 
forM / forM_ 
while / do...while 
N/A 
return 
N/A
●繰り返しの例import Control.Monad -- forMを定義しているモジュール main :: IO () main = do let prompt = "Input your name: " let message = "Hello, " forM_ [1..5] $ i -> do putStr prompt name <- getLine putStrLn $ message ++ name 
Scala v.s. Haskell
●Haskellのreturn 
●モナドでない値をモナドで使うためのもの 
●制御構造ではない 
●例getSmilingLine = do line <- getLine return $ line ++ " (^_^)" returnがたまたま最後の行にあるので値を "return"しているように見える 
Scala v.s. Haskell
●戻らない例 import Control.Monad main :: IO () main = do let prompt = "Input your name: " let message = "Hello, " forM_ [1..5] $ i -> do putStr prompt name <- getLine if name /= "" then do putStrLn $ message ++ name return () else putStrLn "Empty name is not allowed." 
Scala v.s. Haskell
●こういう時はどう書くか? 
●再帰が一番無難な気がします loop :: IO () loop = do let prompt = "Input your name: " let message = "Hello, " putStr prompt name <- getLine if name /= "" then putStrLn $ message ++ name else do putStrLn "Empty name is not allowed." loop main :: IO () main = loop 
Scala v.s. Haskell
●対応表(変数) 
●Haskellでも再代入できる 
Scala v.s. Haskell 
Scala 
Haskell 
val x = 1 
x = 1 
do記法の中では let x = 1 
def fun = ... 
fun = ... 
var x = 1 
varX <- newMVar 1 
x = 2 (再代入) 
modifyMVar_ varX (const $ return 2) 
x (varの参照) 
x <- readMVar varX
●MVar 
●Control.Concurrent.MVarモジュールで定義されている 
●名前の通り並行用なので、複数スレッドで競合が発生したりしないようにできる 
●が、普通に書き換え可能な変数としても使える 
Haskellで書く手続き型プログラム
●MVarの操作 
●MVarの操作はIOモナドの中でできるようになっている 
●とりあえずはdoの中でおこなえばOK 
●初期化 
●var <- newMVar 初期値 
●読み出し 
●x <- readMVar var 
●更新 
●modifyMVar_ var (x -> 新しい値) 
●アトミックに書き換えられる 
●新しい値はIOモナドの値にしたいのでreturnを使って返す 
●古い値を使わない時はconstで定数関数にすればいい (_ -> ... でもOK) 
Haskellで書く手続き型プログラム
●例 import Control.Concurrent.MVar main :: IO () main = do x <- newMVar 0 val <- readMVar x putStrLn $ "x = " ++ (show val) modifyMVar_ x (const $ return (val + 1)) val <- readMVar x putStrLn $ "x = " ++ (show val) 
Haskellで書く手続き型プログラム
●例: 繰り返しでも使える import Control.Monad import Control.Concurrent.MVar main :: IO () main = do varPrompt <- newMVar "Input your name: " -- Stringでも使える let message = "Hello, " forM_ [1..5] $ i -> do prompt <- readMVar varPrompt putStr prompt name <- getLine putStrLn $ message ++ name modifyMVar_ varPrompt (const $ return "Input your name again: ") 
Haskellで書く手続き型プログラム
●STM 
●Software Transactional Memory 
●Control.Concurrent.STMモジュールで定義されている 
●今回の話の範囲ではMVarとほぼ同じ 
●STMモナドの中でread、writeで変更ができるのでmodifyMVar_と比較するとよ り手続き的に書けるかも 
●並行プログラムで使う場合はロックの使い方が異なるので違いがでて くる 
●MVar: ロックを使用 
●STM: 楽観的ロック(ほぼロックフリー) 
Haskellで書く手続き型プログラム
●STMの操作 
●STMの操作はSTMモナドの中でできるようになっている 
●IOモナドの中でSTMの操作をおこなうには、STMモナドをIOモナドに変換する関 数(atomically)を使えばよい 
●初期化 
●var <- newTVarIO 初期値 
●読み出し 
●x <- atomically $ readTVar var 
●変更 
●atomically $ do val <- readTVar var -- 古い値が必要なければ読まなくてもいい writeTVar var (新しい値) 
Haskellで書く手続き型プログラム
●HaskellのArray 
●Data.Arrayモジュールで定義されている 
●Array型のMVarを使えば配列も手続き的に使えるのではないか? 
Haskellで書く手続き型プログラム
●Data.Arrayでは更新が非破壊的に行われる 
●1個の要素を更新するためにも配列全体をコピーして新しい配列を作る 
●更新が少ない配列やIOを使いたくないときには使える 
Haskellで書く手続き型プログラム
●IOArray 
●破壊的に書き込める配列 
●IOモナドの中で使用できる 
●初期化 
●arr <- newListArray インデックスの範囲 初期値 
●読み出し 
●x <- readArray arr インデックス 
●書込み 
●writeArray arr インデックス 新しい値 
Haskellで書く手続き型プログラム
●STArray 
●破壊的に書き込める配列 
●STモナドの中で使用できる 
●使い方はIOArrayとほぼ同じだが、runSTArrayという関数を使うとData.Arrayに 戻せるのでIOにしたくないときに使える 
●使い方 
●runSTArray (STArrayの操作) 
●stSortArray arr = runSTArray $ do stArr <- thaw arr -- Data.ArrayをSTArrayに変換 (thaw: 解凍) ioSort stArr return stArr -- STArrayをreturnするとData.Arrayに変換される 
Haskellで書く手続き型プログラム
●Shelly 
●シェルスクリプトを書くためのライブラリ 
●http://hackage.haskell.org/packages/archive/shelly/latest/doc/html/Shelly.html 
●使い方 
●shelly $ do (シェルスクリプト用の関数呼び出し) 
●run コマンド 引数のリスト 
●-|- : パイプ 
●lastExitCode 
●echo 文字列 
●... 
Haskellで書く手続き型プログラム
●ファイルの先頭に以下のようなおまじないを書く#!/usr/bin/env runhaskell {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE ExtendedDefaultRules #-} {-# OPTIONS_GHC -fno-warn-type-defaults #-} import Shelly import qualified Data.Text.Lazy as LT default (LT.Text) 
Haskellで書く手続き型プログラム
●shellyの後のdoの中はShモナド 
●IOモナドではないのでこのままではMVar等が使えない 
Haskellで書く手続き型プログラム
●こういう時はliftIOを使えばよい 
●多くの入出力ライブラリのモナドはIOモナドの上に積み上げて作られている 
●Shモナドは ReaderT (IORef State) IO a と同等 
●liftIOを使えばIOモナドで動く処理をこうしたモナドで動かすことができる 
Haskellで書く手続き型プログラム
●Haskellコードの読み方 
●Haskellで書く手続き型プログラム 
●変数(MVar, STM) 
●配列(IOArray) 
●シェルスクリプト(Shelly) 
●Haskellは手続き型プログラミング言語です 
まとめ

Weitere ähnliche Inhalte

Was ist angesagt?

プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けープログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けーTanUkkii
 
Java8 lambdas chapter1_2
Java8 lambdas chapter1_2Java8 lambdas chapter1_2
Java8 lambdas chapter1_2yo0824
 
GitHub での Haskell の色が変わったんで
GitHub での Haskell の色が変わったんでGitHub での Haskell の色が変わったんで
GitHub での Haskell の色が変わったんでNobutada Matsubara
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行guest5f4320
 
サーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよサーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよkoji lin
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
Introduction to Spray at Kansai Functional Programming
Introduction to Spray at Kansai Functional ProgrammingIntroduction to Spray at Kansai Functional Programming
Introduction to Spray at Kansai Functional ProgrammingSuguru Hamazaki
 
ゼロから始めるScala文法 (再)
ゼロから始めるScala文法 (再)ゼロから始めるScala文法 (再)
ゼロから始めるScala文法 (再)Suguru Hamazaki
 
ECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングTanUkkii
 

Was ist angesagt? (12)

Spectron
SpectronSpectron
Spectron
 
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けープログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
プログラミング言語のパラダイムシフトーScalaから見る関数型と並列性時代の幕開けー
 
Java8 lambdas chapter1_2
Java8 lambdas chapter1_2Java8 lambdas chapter1_2
Java8 lambdas chapter1_2
 
GitHub での Haskell の色が変わったんで
GitHub での Haskell の色が変わったんでGitHub での Haskell の色が変わったんで
GitHub での Haskell の色が変わったんで
 
Lecture3
Lecture3Lecture3
Lecture3
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行
 
サーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよサーバーサイドでの非同期処理で色々やったよ
サーバーサイドでの非同期処理で色々やったよ
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
Introduction to Spray at Kansai Functional Programming
Introduction to Spray at Kansai Functional ProgrammingIntroduction to Spray at Kansai Functional Programming
Introduction to Spray at Kansai Functional Programming
 
ゼロから始めるScala文法 (再)
ゼロから始めるScala文法 (再)ゼロから始めるScala文法 (再)
ゼロから始めるScala文法 (再)
 
MoteMote Compiler Plugin
MoteMote Compiler PluginMoteMote Compiler Plugin
MoteMote Compiler Plugin
 
ECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミングECMAScript6による関数型プログラミング
ECMAScript6による関数型プログラミング
 

Ähnlich wie ScalaプログラマのためのHaskell入門

Vim scriptとJavaとHaskell
Vim scriptとJavaとHaskellVim scriptとJavaとHaskell
Vim scriptとJavaとHaskellaiya000
 
言語アップデート -Scala編-
言語アップデート -Scala編-言語アップデート -Scala編-
言語アップデート -Scala編-Kota Mizushima
 
すごいHaskell読書会#1 in 大阪
すごいHaskell読書会#1 in 大阪すごいHaskell読書会#1 in 大阪
すごいHaskell読書会#1 in 大阪yashigani
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdfHiroshi Ono
 
(Ruby使いのための)Scalaで学ぶ関数型プログラミング
(Ruby使いのための)Scalaで学ぶ関数型プログラミング(Ruby使いのための)Scalaで学ぶ関数型プログラミング
(Ruby使いのための)Scalaで学ぶ関数型プログラミングOuka Yuka
 
並行プログラミングと継続モナド
並行プログラミングと継続モナド並行プログラミングと継続モナド
並行プログラミングと継続モナドKousuke Ruichi
 
Scalamacrosについて
ScalamacrosについてScalamacrosについて
Scalamacrosについてdekosuke
 
2013-12-08 西区プログラム勉強会
2013-12-08 西区プログラム勉強会2013-12-08 西区プログラム勉強会
2013-12-08 西区プログラム勉強会Takatoshi Murakami
 
JavaScript 講習会 #1
JavaScript 講習会 #1JavaScript 講習会 #1
JavaScript 講習会 #1Susisu
 
Haskellday rf
Haskellday rfHaskellday rf
Haskellday rfrf0444
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Ransui Iso
 
GNU awk (gawk) を用いた Apache ログ解析方法
GNU awk (gawk) を用いた Apache ログ解析方法GNU awk (gawk) を用いた Apache ログ解析方法
GNU awk (gawk) を用いた Apache ログ解析方法博文 斉藤
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8y_taka_23
 

Ähnlich wie ScalaプログラマのためのHaskell入門 (20)

Vim scriptとJavaとHaskell
Vim scriptとJavaとHaskellVim scriptとJavaとHaskell
Vim scriptとJavaとHaskell
 
Haskell で CLI
Haskell で CLIHaskell で CLI
Haskell で CLI
 
言語アップデート -Scala編-
言語アップデート -Scala編-言語アップデート -Scala編-
言語アップデート -Scala編-
 
すごいHaskell読書会#1 in 大阪
すごいHaskell読書会#1 in 大阪すごいHaskell読書会#1 in 大阪
すごいHaskell読書会#1 in 大阪
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
BOF1-Scala02.pdf
BOF1-Scala02.pdfBOF1-Scala02.pdf
BOF1-Scala02.pdf
 
Hokuriku Scala 1
Hokuriku Scala 1Hokuriku Scala 1
Hokuriku Scala 1
 
Scala on Hadoop
Scala on HadoopScala on Hadoop
Scala on Hadoop
 
(Ruby使いのための)Scalaで学ぶ関数型プログラミング
(Ruby使いのための)Scalaで学ぶ関数型プログラミング(Ruby使いのための)Scalaで学ぶ関数型プログラミング
(Ruby使いのための)Scalaで学ぶ関数型プログラミング
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行
 
並行プログラミングと継続モナド
並行プログラミングと継続モナド並行プログラミングと継続モナド
並行プログラミングと継続モナド
 
Scalamacrosについて
ScalamacrosについてScalamacrosについて
Scalamacrosについて
 
2013-12-08 西区プログラム勉強会
2013-12-08 西区プログラム勉強会2013-12-08 西区プログラム勉強会
2013-12-08 西区プログラム勉強会
 
JavaScript 講習会 #1
JavaScript 講習会 #1JavaScript 講習会 #1
JavaScript 講習会 #1
 
Haskellday rf
Haskellday rfHaskellday rf
Haskellday rf
 
20151121
2015112120151121
20151121
 
Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3Lisp Tutorial for Pythonista : Day 3
Lisp Tutorial for Pythonista : Day 3
 
GNU awk (gawk) を用いた Apache ログ解析方法
GNU awk (gawk) を用いた Apache ログ解析方法GNU awk (gawk) を用いた Apache ログ解析方法
GNU awk (gawk) を用いた Apache ログ解析方法
 
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
思ったほど怖くない! Haskell on JVM 超入門 #jjug_ccc #ccc_l8
 
Testman
TestmanTestman
Testman
 

ScalaプログラマのためのHaskell入門