More Related Content Similar to すごいHaskell楽しく学ぼう 第6章 Similar to すごいHaskell楽しく学ぼう 第6章 (20) More from aomori ringo (7) すごいHaskell楽しく学ぼう 第6章2. 1986-2005 ◎ Twitter: @aomoriringo
◎ 最近使ってる言語
◦ C#
◎ 趣味
2005-2011 ◦ Mathematica
2011- ◎ Haskell歴
◦ 2ヶ月未満
3. ◎ いくつかの関数や型、型クラスなどを定義したファイル
◎ Haskellのプログラムはモジュールの集合
◎ コードをモジュールに分割するとしあわせ
◦ 再利用性を高める
◦ 管理・修正しやすくする
4. ◎ モジュールをインポートする
◎ 標準モジュールを使ってみる
◦ 標準モジュールでいろいろ作ってみる
◦ foldl, foldl’
◦ 連想リスト
◎ 自分でモジュールを作ってみる
6. ◎ 全てをインポート
import Data.List
◎ nub, sortのみをインポート
import Data.List (nub, sort)
◎ nub以外の全てをインポート
import Data.List hiding (nub)
8. ◎ 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
9. ◎ 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)
11. ◎ Hackage
◦ hackage.haskell.org/packages/hackage.html
◎ Hoogle
◦ http://www.haskell.org/hoogle/
◦ 標準モジュールのソースコードが見れます
◎ Hayoo!
◦ http://holumbus.fh-wedel.de/hayoo/hayoo.html
12. ◎ 単語の個数を調べる
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)]
13. ◎ 文字列を空白で区切られた文字列のリストに変換する
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”]
14. ◎ リストの同じ要素をグループ化する
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”]]
15. ◎ リストを昇順に並べ替える
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”]
17. ◎ 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 “”
[]
18. ◎ あるリストが別のリストに含まれるかどうかを調べる
ghci> :t isIn
isIn :: [a] -> [a] -> Bool
ghci> “art” `isIn` “party”
True
ghci> [1,2] `isIn` [1,3,5]
False
19. ◎ リストに対して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], []]
20. ◎ 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
21. “art” `isPrefixOf` “party” -- False
“art” `isPrefixOf` “arty” -- True
“art” `isPrefixOf` “rty” -- False
“art” `isPrefixOf` “ty” -- False
“art” `isPrefixOf` “y” -- False
22. ◎ リストのうち、述語を満たすものがあるかどうかを返す
ghci> :t any
any :: (a -> Bool) -> [a] -> Bool
ghci> any (>4) [1,2,3]
False
ghci> any id [False, False, True]
True
23. ◎ isInの定義
isIn :: (Eq a) => [a] -> [a] -> Bool
needle `isIn` haystack =
any (needle `isPrefixOf`) (tails haystack)
needle: 針。見つけたいリスト
haystack: 干し草の山。検索対象のリスト
24. ◎ Data.List.isPrefixOf
◦ 前方一致
◦ さっき使った
◎ Data.List.isSuffixOf
◦ 後方一致
◎ Data.List.isInfixOf
◦ 中間一致
◦ さっき作った(isIn)
25. ◎ シーザー暗号
◦ 平文の各文字を辞書順にn文字シフトして作る
26. ◎ 文字<->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]
27. ◎ 指定した文字数分シフトする
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
28. ghci> encode 3 “hey mark”
“kh|#pdun”
ghci> decode 3 “kh|#pdun”
“hey mark”
ghci> decode 3 $ encode 3 “abc”
“abc”
29. ◎ 各桁の数の合計がnになる最初の自然数をみつける
ghci> :t firstTo
firstTo :: Int -> Int
ghci> firstTo 1
1
ghci> firstTo 13
49
30. ◎ 文字を数に変換する
ghci> :t digitToInt
digitToInt :: Char -> Int
ghci> digitToInt ‘2’
2
ghci> digitToInt ‘F’
15
ghci> digitToInt ‘z’
*** Exception: Char.digitToInt: not a digit 'z'
31. ◎ 各桁の数の和を返す
digitSum :: Int -> Int
digitSum = sum . map digitToInt . show
ghci> digitSum 30
3
ghci> digitSum 1234
10
32. ghci> :t find
find :: (a -> Bool) -> [a] -> Maybe a
ghci> find (>4) [3,4,5,6,7] Nothing | Just a
Just 5
ghci> find odd [2,4,6,8,9]
Just 9
ghci> find (==‘z’) “haskell”
Nothing
33. ◎ firstToの定義
firstTo :: Int -> Maybe Int
firstTo n =
find (¥x -> digitSum x == n) [1..]
ghci> firstTo 27
Just 999
ghci> firstTo 40
Just 49999
35. ghci> foldl (+) 0 [1..2000000]
2000001000000
◦ 遅い
◦ サイズ、環境によってはスタックオーバーフロー
ghci> Data.List.foldl’ (+) 0 [1..2000000]
2000001000000
◦ foldlより速い
◦ オーバーフローしない
36. 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
37. ◎ 正格な(遅延でない)左畳み込み
foldl’ (+) 0 [1,2,3] =
foldl’ (+) 1 [2,3] =
foldl’ (+) 3 [3] =
foldl’ (+) 6 [] =
6
39. ◎ 添字として任意の型を使用する配列
◎ 呼び方はいろいろ
◦ Map
◦ Dictionary
◦ Hash
40. ◎ タプルを連想リストっぽく扱う
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
41. ◎ 連想リスト(Map)のモジュール
◦ Data.Map.lookup
◦ Data.Map.insert
◦ Data.Map.delete
◦ Data.Map.size
◦ etc..
42. ◎ 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
43. 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
44. ◎ 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”)]
45. ◎ 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)]
47. ◎ 先頭にモジュール宣言を書く
-- Foo.hs
module Foo where
◦ モジュール名とファイル名は同じにしなければならない
◎ モジュールの中身を
◦ 全て公開したい(エクスポート)
module Foo where
◦ 一部だけ公開したい
◦ module Foo (hoge, var) where
48. ◎ 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
49. ◎ 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 -- コンパイルエラー
50. ◎ モジュールは階層構造を持つことが可能
◎ 階層構造は「A.B.C」のようにドット「.」で表す
◎ A.B.Cというモジュール名にした場合は、
A/B/C.hsというファイル構成にする
51. ◎ 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
52. ◎ インポート, エクスポートはどちらも範囲を限定できる
◎ 標準モジュールを調べる, 使う, 理解するサイクルを
身につけたい
◎ 「こんなのないかな?」と思ったらHoogleとかで探す
◎ モジュールのエクスポートを気にしてきれいなコードを
書きたいですね