すごいhaskell楽しく学ぼう 第6章

52
@aomoriringo

Upload: aomori-ringo

Post on 31-May-2015

4.995 views

Category:

Education


0 download

DESCRIPTION

スタートHaskell2で発表

TRANSCRIPT

Page 1: すごいHaskell楽しく学ぼう 第6章

@aomoriringo

Page 2: すごいHaskell楽しく学ぼう 第6章

1986-2005

2005-2011

2011-

◎ Twitter: @aomoriringo

◎最近使ってる言語 ◦ C#

◎趣味 ◦ Mathematica

◎ Haskell歴 ◦ 2ヶ月未満

Page 3: すごいHaskell楽しく学ぼう 第6章

◎ いくつかの関数や型、型クラスなどを定義したファイル

◎ Haskellのプログラムはモジュールの集合

◎ コードをモジュールに分割するとしあわせ ◦ 再利用性を高める

◦ 管理・修正しやすくする

Page 4: すごいHaskell楽しく学ぼう 第6章

◎ モジュールをインポートする

◎ 標準モジュールを使ってみる ◦ 標準モジュールでいろいろ作ってみる

◦ foldl, foldl’

◦ 連想リスト

◎ 自分でモジュールを作ってみる

Page 5: すごいHaskell楽しく学ぼう 第6章

モジュールをインポートする

Page 6: すごいHaskell楽しく学ぼう 第6章

◎ 全てをインポート import Data.List

◎ nub, sortのみをインポート import Data.List (nub, sort)

◎ nub以外の全てをインポート import Data.List hiding (nub)

Page 7: すごいHaskell楽しく学ぼう 第6章

import qualified Data.Map

◦ Data.Map.filterのように参照

import qualified Data.Map as M

◦ M.filterのように参照

Page 8: すごいHaskell楽しく学ぼう 第6章

◎ module Fooにhogeとbarがあるとき

宣言 インポートされるもの 参照の方法

import Foo hoge, bar hoge, bar Foo.hoge, Foo.bar

import Foo () (なし)

import Foo (hoge) hoge hoge, Foo.hoge

import Foo hiding (hoge) bar bar, Foo.bar

import qualified Foo hoge, bar Foo.hoge, Foo.bar

import Foo as F hoge, bar hoge, bar F.hoge, F.bar

import qualified Foo as F hoge, bar F.hoge, F.bar

Page 9: すごいHaskell楽しく学ぼう 第6章

◎ Data.Listをインポート ghci> :m + Data.List

ghci> :m + Data.List Data.Map Data.Set

◎ Data.Listのインポートを解除 ghci> :m – Data.List

◎ importも使用可能 ghci> import Data.List (nub, sort)

ghci> import qualified Data.Map as M hiding (foldl)

Page 10: すごいHaskell楽しく学ぼう 第6章

標準モジュールを使ってみる

Data.List

Data.Char

Data.Map

Page 11: すごいHaskell楽しく学ぼう 第6章

◎ Hackage ◦ hackage.haskell.org/packages/hackage.html

◎ Hoogle ◦ http://www.haskell.org/hoogle/

◦ 標準モジュールのソースコードが見れます

◎ Hayoo! ◦ http://holumbus.fh-wedel.de/hayoo/hayoo.html

Page 12: すごいHaskell楽しく学ぼう 第6章

◎ 単語の個数を調べる

ghci> :t wordNums

wordNums :: String -> [(String,Int)]

ghci> wordNums "a haskell learn haskell a a learn good"

[("a",3),("good",1),("haskell",2),("learn",2)]

Page 13: すごいHaskell楽しく学ぼう 第6章

◎ 文字列を空白で区切られた文字列のリストに変換する

ghci> :t words

words :: String -> [String]

ghci> words “hey these are the words”

[“hey”, “these”, “are”, “the”, “words”]

ghci> words “hey these are the words”

[“hey”, “these”, “are”, “the”, “words”]

Page 14: すごいHaskell楽しく学ぼう 第6章

◎ リストの同じ要素をグループ化する

ghci> :t group

group :: Eq a => [a] -> [[a]]

ghci> group [1,1,1,2,2,2,3,3,2,2,5,7]

[[1,1,1],[2,2,2],[3,3],[2,2],[5],[7]]

ghci> group [“hoge”, “var”, “var”, “hoge”, “hoge”]

[[“hoge”], [“var”, “var”], [“hoge”, “hoge”]]

Page 15: すごいHaskell楽しく学ぼう 第6章

◎ リストを昇順に並べ替える

ghci> :t sort

sort :: Ord a => [a] -> [a]

ghci> sort [5,4,3,7,2,1]

[1,2,3,4,5,7]

ghci> sort [“hoge”, “var”, “var”, “hoge”, “hoge”]

[“hoge”, “hoge”, “hoge”, “var”, “var”]

Page 16: すごいHaskell楽しく学ぼう 第6章

文字列を単語に区切って (words)

→ソートして (sort)

→グループ化して (group)

→グループごとに数を数えれば

できそうですね!

Page 17: すごいHaskell楽しく学ぼう 第6章

◎ wordNumsの定義 wordNums :: String -> [(String,Int)]

wordNums = map (¥ws -> (head ws, length ws)) .

group . sort . words

ghci> wordNums “a b c b c”

[("a",1),(“b",2),(“c",2)]

ghci> wordNums “”

[]

Page 18: すごいHaskell楽しく学ぼう 第6章

◎ あるリストが別のリストに含まれるかどうかを調べる

ghci> :t isIn

isIn :: [a] -> [a] -> Bool

ghci> “art” `isIn` “party”

True

ghci> [1,2] `isIn` [1,3,5]

False

Page 19: すごいHaskell楽しく学ぼう 第6章

◎ リストに対してtailを繰り返し適用する

ghci> :t tails

tails :: [a] -> [[a]]

ghci> tails “party”

[“party”, “arty”, “rty”, “ty”, “y”, “”]

ghci> tails [1,2,3]

[[1,2,3], [2,3], [3], []]

Page 20: すごいHaskell楽しく学ぼう 第6章

◎ 2つ目のリストが1つ目のリストで 始まっているかどうかを返す

ghci> :t isPrefixOf

isPrefixOf :: String -> String -> Bool

ghci> “hawaii” `isPrefixOf` “hawaii joe”

True

ghci> “haha” `isPrefixOf` “ha”

False

ghci> “ha” `isPrefixOf` “haha”

True

Page 21: すごいHaskell楽しく学ぼう 第6章

“art” `isPrefixOf` “party” -- False

“art” `isPrefixOf` “arty” -- True

“art” `isPrefixOf` “rty” -- False

“art” `isPrefixOf` “ty” -- False

“art” `isPrefixOf` “y” -- False

Page 22: すごいHaskell楽しく学ぼう 第6章

◎ リストのうち、述語を満たすものがあるかどうかを返す

ghci> :t any

any :: (a -> Bool) -> [a] -> Bool

ghci> any (>4) [1,2,3]

False

ghci> any id [False, False, True]

True

Page 23: すごいHaskell楽しく学ぼう 第6章

◎ isInの定義 isIn :: (Eq a) => [a] -> [a] -> Bool

needle `isIn` haystack =

any (needle `isPrefixOf`) (tails haystack)

needle: 針。見つけたいリスト

haystack: 干し草の山。検索対象のリスト

Page 24: すごいHaskell楽しく学ぼう 第6章

◎ Data.List.isPrefixOf ◦ 前方一致

◦ さっき使った

◎ Data.List.isSuffixOf ◦ 後方一致

◎ Data.List.isInfixOf ◦ 中間一致

◦ さっき作った(isIn)

Page 25: すごいHaskell楽しく学ぼう 第6章

◎ シーザー暗号 ◦ 平文の各文字を辞書順にn文字シフトして作る

Page 26: すごいHaskell楽しく学ぼう 第6章

◎ 文字<->Unicode変換 ghci> :t ord

ord :: Char -> Int

ghci> ord ‘a’

97

ghci> :t chr

chr :: Int -> Char

ghci> chr 97

‘a’

ghci> map ord “abcdefgh”

[97,98,99,100,101,102,103,104]

Page 27: すごいHaskell楽しく学ぼう 第6章

◎ 指定した文字数分シフトする encode :: Int -> String -> String

encode offset msg =

map (¥c -> chr $ ord c + offset) msg

◎ 指定した文字数分逆にシフトする decode :: Int -> String -> String

decode shift msg = encode (negate shift) msg

Page 28: すごいHaskell楽しく学ぼう 第6章

ghci> encode 3 “hey mark”

“kh|#pdun”

ghci> decode 3 “kh|#pdun”

“hey mark”

ghci> decode 3 $ encode 3 “abc”

“abc”

Page 29: すごいHaskell楽しく学ぼう 第6章

◎ 各桁の数の合計がnになる最初の自然数をみつける

ghci> :t firstTo

firstTo :: Int -> Int

ghci> firstTo 1

1

ghci> firstTo 13

49

Page 30: すごいHaskell楽しく学ぼう 第6章

◎ 文字を数に変換する

ghci> :t digitToInt

digitToInt :: Char -> Int

ghci> digitToInt ‘2’

2

ghci> digitToInt ‘F’

15

ghci> digitToInt ‘z’

*** Exception: Char.digitToInt: not a digit 'z'

Page 31: すごいHaskell楽しく学ぼう 第6章

◎ 各桁の数の和を返す

digitSum :: Int -> Int

digitSum = sum . map digitToInt . show

ghci> digitSum 30

3

ghci> digitSum 1234

10

Page 32: すごいHaskell楽しく学ぼう 第6章

ghci> :t find

find :: (a -> Bool) -> [a] -> Maybe a

ghci> find (>4) [3,4,5,6,7]

Just 5

ghci> find odd [2,4,6,8,9]

Just 9

ghci> find (==‘z’) “haskell”

Nothing

Nothing | Just a

Page 33: すごいHaskell楽しく学ぼう 第6章

◎ firstToの定義 firstTo :: Int -> Maybe Int

firstTo n =

find (¥x -> digitSum x == n) [1..]

ghci> firstTo 27

Just 999

ghci> firstTo 40

Just 49999

Page 34: すごいHaskell楽しく学ぼう 第6章

foldl, foldl’

Page 35: すごいHaskell楽しく学ぼう 第6章

ghci> foldl (+) 0 [1..2000000]

2000001000000 ◦ 遅い

◦ サイズ、環境によってはスタックオーバーフロー

ghci> Data.List.foldl’ (+) 0 [1..2000000]

2000001000000 ◦ foldlより速い

◦ オーバーフローしない

Page 36: すごいHaskell楽しく学ぼう 第6章

foldl (+) 0 [1,2,3] =

foldl (+) (0 + 1) [2,3] =

foldl (+) ((0 + 1) + 2) [3] =

foldl (+) (((0 + 1) + 2) + 3) [] =

((0 + 1) + 2) + 3 =

(1 + 2) + 3 =

3 + 3 =

6

Page 37: すごいHaskell楽しく学ぼう 第6章

◎ 正格な(遅延でない)左畳み込み

foldl’ (+) 0 [1,2,3] =

foldl’ (+) 1 [2,3] =

foldl’ (+) 3 [3] =

foldl’ (+) 6 [] =

6

Page 38: すごいHaskell楽しく学ぼう 第6章

連想リスト

Page 39: すごいHaskell楽しく学ぼう 第6章

◎ 添字として任意の型を使用する配列

◎ 呼び方はいろいろ ◦ Map

◦ Dictionary

◦ Hash

Page 40: すごいHaskell楽しく学ぼう 第6章

◎ タプルを連想リストっぽく扱う ghci> :t lookup

lookup :: Eq a => a -> [(a,b)] -> Maybe b

ghci> lookup “b” [(“a”,1), (“b”,2), (“c”,3)]

Just 2

ghci> lookup “k” [(“a”,1), (“b”,2), (“c”,3)]

Nothing

Page 41: すごいHaskell楽しく学ぼう 第6章

◎連想リスト(Map)のモジュール ◦ Data.Map.lookup

◦ Data.Map.insert

◦ Data.Map.delete

◦ Data.Map.size

◦ etc..

Page 42: すごいHaskell楽しく学ぼう 第6章

◎ Data.Mapで連想リストを表す型

◎ keyとvalueの型を持つ

ghci> let m = Data.Map.fromList [(“foo”,1), (“bar”,2)]

ghci> :t m

m :: Data.Map.Map [Char] Integer

ghci> let m2 = Data.Map.fromList [(‘a’, True), (‘b’, False)]

ghci> :t m2

m2 :: Data.Map.Map Char Bool

Page 43: すごいHaskell楽しく学ぼう 第6章

ghci> import qualified Data.Map as Map

◎ keyで検索する ghci> let m = Map.fromList [(“a”,1), (“b”,2)]

ghci> Map.lookup “b” m

Just 2

ghci> Map.lookup “c” m

Nothing

◎ key=“c”, value=3の要素を挿入する ghci> let m2 = Map.insert “c” 3 m

ghci> Map.lookup “c” m2

Just 3

ghci> Map.size m2

3

Page 44: すごいHaskell楽しく学ぼう 第6章

◎ valueに関数を適用して新しいMapを作る

ghci> m2

fromList [("a",1),("b",2),("c",3)]

ghci> Map.map (^2) m2

fromList [("a",1),("b",4),("c",9)]

ghci> Map.map show m2

fromList [(“a”,”1”), (“b”,”2”), (“c”, “3”)]

Page 45: すごいHaskell楽しく学ぼう 第6章

◎ keyが重複した際の振る舞いを決める

ghci> Map.fromList [(1,2),(1,50),(1,10),(2,3)]

fromList [(1,10),(2,3)]

ghci> Map.fromListWith (+) [(1,2),(1,50),(1,10),(2,3)]

fromList [(1,62),(2,3)]

ghci> Map.fromListWith max [(1,2),(1,50),(1,10),(2,3)]

fromList [(1,50),(2,3)]

Page 46: すごいHaskell楽しく学ぼう 第6章

モジュールを作る

Page 47: すごいHaskell楽しく学ぼう 第6章

◎ 先頭にモジュール宣言を書く -- Foo.hs module Foo where ◦ モジュール名とファイル名は同じにしなければならない

◎ モジュールの中身を ◦ 全て公開したい(エクスポート) module Foo where

◦ 一部だけ公開したい

◦ module Foo (hoge, var) where

Page 48: すごいHaskell楽しく学ぼう 第6章

◎ test1/Nums.hs

module Nums where

double x = x + x

quadruple x = double x + double x

◎ test1/Main.hs

import Nums

double2 = Nums.double 2

quadruple4 = Nums.quadruple 4

Page 49: すごいHaskell楽しく学ぼう 第6章

◎ test1/Nums.hs

module Nums (double) where

double x = x + x

quadruple x = double x + double x

◎ test1/Main.hs

import Nums

double2 = Nums.double 2 -- OK

quadruple4 = Nums.quadruple 4 -- コンパイルエラー

Page 50: すごいHaskell楽しく学ぼう 第6章

◎ モジュールは階層構造を持つことが可能

◎ 階層構造は「A.B.C」のようにドット「.」で表す

◎ A.B.Cというモジュール名にした場合は、 A/B/C.hsというファイル構成にする

Page 51: すごいHaskell楽しく学ぼう 第6章

◎ test1/Figure/Sphere.hs

module Figure.Sphere where

Area radius = 4 * pi * (radius ^ 2)

◎ test1/Figure/Rectangle.hs

module Figure.Rectangle where

Area width height = width * height

◎ test1/Main.hs

import qualified Figure.Sphere as Sphere

import qualified Figure.Rectangle as Rect

sphereArea = Sphere.Area

rectArea = Rect.Area

Page 52: すごいHaskell楽しく学ぼう 第6章

◎ インポート, エクスポートはどちらも範囲を限定できる

◎ 標準モジュールを調べる, 使う, 理解するサイクルを 身につけたい

◎ 「こんなのないかな?」と思ったらHoogleとかで探す

◎ モジュールのエクスポートを気にしてきれいなコードを 書きたいですね