An intro to lists

In [1]:
let lostNumbers = [4,8,15,16,23,42]
lostNumbers
[4,8,15,16,23,42]
  • listは同じ型のデータをもつ
  • "hello"['h','e','l','l','o']`のシンタックスシュガー、文字列はlistなので
In [2]:
lostNumbers' = [4,8,15,16,23,42]
lostNumbers'
[4,8,15,16,23,42]

GHC 8からはghciでもletが不要になった。

リスト演算子

In [3]:
[1,2,3,4] ++ [9,10,11,12]
"hello" ++ " " ++ "world"
['w','o'] ++ ['o','t']
[1,2,3,4,9,10,11,12]
"hello world"
"woot"
  • ++ list結合
    • 2つのリストを結合するとき、Haskellは内部で ++の左側のリストを走査するので、大きなリストを扱うときは注意
In [4]:
'A':"SMALL CAT"
5:[1,2,3,4,5]
"ASMALL CAT"
[5,1,2,3,4,5]
  • : 先頭に要素を追加

    • [1,2,3]1:2:3:[]のシンタックスシュガー

    Note: [], [[]], [[],[],[]]は全て異なるものである最初は空リスト、2番目は空リストを含むリスト、最後は3つの空リストを含むリスト

In [5]:
"Steve Buscemi" !! 6
[9.4,33.2,96.2,11.2,23.25] !! 1
'B'
33.2
  • !! 特定のindexの要素を取りだす
In [6]:
let b = [[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
b
b ++ [[1,1,1,1]] 
[6,6,6]:b
b !! 2
[[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
[[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3],[1,1,1,1]]
[[6,6,6],[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
[1,2,2,3,4]
  • listは入れ子にすることもできる
  • list中に複数のリストを保持するとき、長さが異なってもいいが内包する各リストの型が異なることは許されない
In [7]:
[3,2,1] > [2,1,0] 
[3,2,1] > [2,10,100]
[3,4,2] > [3,4]
[3,4,2] > [2,4]
[3,4,2] == [3,4,2]
True
True
True
True
True
  • <, <=, >>= 辞書的な比較
    • 先頭要素を比較していき、もし同じ値の場合次の要素の比較をする

list関数

In [8]:
head [5,4,3,2,1]
5
  • head 先頭要素を返す
In [9]:
tail [5,4,3,2,1]
[4,3,2,1]
  • tail 先頭要素以外のリストを返す
In [10]:
last [5,4,3,2,1]
1
  • last 末尾要素を返す
In [11]:
init [5,4,3,2,1]
[5,4,3,2]
  • init 末尾要素以外のリストを返す
In [12]:
head []
tail []
last []
init []
Prelude.head: empty list
  • 上記関数、空リストのときにエラーが起きる点注意
In [13]:
length [5,4,3,2,1]
5
  • length リストの長さを返す
In [14]:
null [1,2,3]
null []
Evaluate
Found:
null []
Why Not:
True
False
True
  • null リストが空リストの場合 Trueを返し、そうで無い場合 False を返
In [15]:
reverse [5,4,3,2,1]
[1,2,3,4,5]
  • reverse リストの要素を逆順にして返す
In [16]:
take 3 [5,4,3,2,1]
take 1 [3,9,3]
take 5 [1,2]
take 0 [6,6,6]
Take on a non-positive
Found:
take 0 [6, 6, 6]
Why Not:
[]
[5,4,3]
[3]
[1,2]
[]
  • take 先頭から指定した数の要素数のリストを返す。0のときは空リストを返す
In [17]:
drop 3 [8,4,2,1,5,6]
drop 0 [1,2,3,4]
drop 100 [1,2,3,4]
[1,5,6]
[1,2,3,4]
[]
  • drop 先頭から指定した数の要素数を取り除いたリストを返す。指定した数がリストの長さ以上の場合は空リストを返す
In [18]:
minimum [8,4,2,1,5,6]
1
  • minimum リストの最小値を返す
In [19]:
maximum [1,9,2,3,4]
9
  • maximum リストの最大値を返す
In [20]:
sum [5,2,1,6,3,2,5,7]
31
  • sum リストの要素の和を返す
In [21]:
product [6,2,1,2]
product [1,2,5,6,7,9,2,0]
24
0

product リストの要素の積を返す

In [22]:
4 `elem` [3,4,5,6]
10 `elem` [3,4,5,6]
True
False
  • elem リストに指定した値が入っている場合 Trueを返し、そうで無い場合 False を返す
    • よく infix functionとして呼ばれる

Texas ranges

In [23]:
[1..20]
['a'..'z']
['A'..'Z']
['A'..'z']
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz"
  • rangeは等差数列で要素が列挙可能なlistを作成する一つの方法
In [24]:
[2,4..20]
[3,6..20]
[2,4,6,8,10,12,14,16,18,20]
[3,6,9,12,15,18]
  • rangeはstepを指定することもできる
  • 2のべき乗みたいな等比数列はうまく生成できない
In [25]:
[0.1, 0.3..1]
[0.1,0.3,0.5,0.7,0.8999999999999999,1.0999999999999999]
  • 浮動小数点のrangeは丸め誤差がでるので使わない方がよい

無限リスト

  • 上限を指定しないことで無限listを作成することができる
  • Haskellは遅延評価と無限listを利用してlist生成のスマートな書き方ができる
    • not smart [13,26..24*13]
    • smart take 24 [13,26..]
    • Haskellは即時に無限リストを評価することはない

無限listを生成する関

In [26]:
take 10 (cycle [1,2,3])
take 12 (cycle "LOL ")
[1,2,3,1,2,3,1,2,3,1]
"LOL LOL LOL "
  • cycle 指定したリストの要素を繰り返す無限listを返す
In [27]:
take 10 (repeat 5)
Use replicate
Found:
take 10 (repeat 5)
Why Not:
replicate 10 5
[5,5,5,5,5,5,5,5,5,5]
  • repeat 指定した値を繰り返す無限listを返す
In [28]:
replicate 10 5
[5,5,5,5,5,5,5,5,5,5]
  • takerepeatを使う場合、 replicate関数を用いて簡単に書ける

I'm a list comprehension

In [29]:
[x*2 | x <- [1..10]]
[2,4,6,8,10,12,14,16,18,20]
  • listだけでは表現しにくい複雑な集合を取りたい場合にリスト内包表記を記述する
In [30]:
[x*2 | x <- [1..10], x >= 6]
[12,14,16,18,20]
In [31]:
[ x | x <- [50..100], x `mod` 7 == 3]
[52,59,66,73,80,87,94]
  • 述語によってfilteringできる
In [32]:
boomBangs xs = [ if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x]
boomBangs [7..13]
["BOOM!","BOOM!","BANG!","BANG!"]
In [33]:
[ x | x <- [10..20], x /= 13, x /= 15, x /= 19]
[10,11,12,14,16,17,18,20]
  • 述語はカンマ区切りで複数指定できる
In [34]:
[ x*y | x <- [2,5,10], y <- [8,10,11]]
[16,20,22,40,50,55,80,100,110]
In [35]:
[ x*y | x <- [2,5,10], y <- [8,10,11], x*y > 50]
[55,80,100,110]
In [36]:
let nouns = ["hobo","frog","pope"]
let adjectives = ["lazy","grouchy","scheming"]
[adjective ++ " " ++ noun | adjective <- adjectives, noun <- nouns]
["lazy hobo","lazy frog","lazy pope","grouchy hobo","grouchy frog","grouchy pope","scheming hobo","scheming frog","scheming pope"]
  • ソースとなるリストも複数指定可能
In [37]:
length' xs = sum [1 | _ <- xs]
length' [5,4,2,1]
length' "hello"
4
5
  • リストからとってきた変数を利用しないときは _と書く
In [38]:
removeNonUppercase st = [ c | c <- st, c `elem` ['A'..'Z']]
removeNonUppercase "Hahaha! Ahahaha!"
removeNonUppercase "IdontLIKEFROGS"
"HA"
"ILIKEFROGS"
In [39]:
let xxs = [[1,3,5,2,3,1,2,4,5],[1,2,3,4,5,6,7,8,9],[1,2,4,2,1,6,3,1,3,2,3,6]]
[ [ x | x <- xs, even x ] | xs <- xxs]
[[2,2,4],[2,4,6,8],[2,4,2,6,2,6]]
  • 集合 - Wikipedia

  • [補足]Pythonにもリスト内包表記がある(Haskellを参考にした)