関数呼び出し、リスト、内包表記 -- Haskell
すごいHaskellたのしく学ぼう!ですが、まず、第一章の中盤まで。 関数呼び出しとリストについて勉強しました。
関数呼び出し
Lisp系などでは、演算子も
(+ 1 1)
のように左に置く(前置)ので、慣れるまでちょっと違和感を感じる事もありますが、Haskellでは演算子は中置できるそうです。
1 + 1
ややっこしいから統一して欲しいという時には、以下のように前置できる。
(+) 1 1
リスト
連結
リスト同士の連結は ++ 演算子で行う。これは中置できる。 で、文字列は文字のリストで表現されているため、文字列の結合も ++ 演算子で行う。
[1, 1, 1] ++ [2, 2, 2] ++ [3, 3, 3] -- [1, 1, 1, 2, 2, 2, 3, 3, 3]
"Hello " ++ "Haskell" -- "Hello Haskell"
C言語などのプログラミングでは ++ はインクリメントの単項演算子ですが、まぁソースの前後を見れば何をやっているのか 何となくはわかりますね。
ランダムアクセス
C言語の配列に添字でアクセスするようにリストの要素に先頭からの位置でアクセスが可能です。
[1, 2, 3, 4, 5] !! 2 -- 3 添字は0から始まる
[[10, 11, 12], [20, 21, 22], [30, 31, 32, 33]] !! 1 -- [20, 21, 22]
[[10, 11, 12], [20, 21, 22], [30, 31, 32, 33]] !! 1 !! 2 -- 22
と、この辺までは、なんとなく理解できました。書き方は違っていますが、考え方は他のプログラミング言語にもよく出てきます。 ここからちょっとややこしくなりました。
比較
まず、リストのまま比較できます。まぁ、これも考え方を少し変えてみれば不思議ではありません。文字列を比較演算子で 比較できる言語は結構あると思います。C言語はstrcmpで0との比較になりますね。
[1, 2, 3] < [1, 2, 4] -- True
[3, 2, 1] == [3, 2, 1] -- True
[2, 4, 6] /= [2, 4, 6] -- False
リスト関係の基本的な関数
- head
- 先頭の要素を返す
- tail
- 先頭を取り除いた残りの要素を返す
- last
- 最後の要素を返す
- init
- 最後を取り除いた残りの要素を返す
- length
- リストの長さを返す
- null
- 空リストかどうかを論理値で返す
- reverse
- リストを逆順にする
- take
-
先頭から指定数の要素をリストとして返す
take 3 [1, 2, 3, 4, 5] -- [1, 2, 3]
- drop
-
先頭からして指数の要素を削除して残りの要素をリストとして返す
drop 2 [1, 2, 3, 4, 5] -- [3, 4, 5]
- maximum
- リスト中の最大の要素を返す
- minimum
- リスト中の最小の要素を返す
- sum
- リストの要素を全て足した値(和)を返す
- product
- リストの要素を全て掛けた値(積)を返す
- elem
-
リストの中に要素が含まれているかを論理値で返す
中置関数で書かれる事が多いそうです。
elem 3 [1, 2, 3, 4, 5] -- True
8 `elem` [1, 2, 3, 4, 5] -- False - cycle
-
リストを永遠に繰り返す無限リストを返す
take 5 (cycle [1, 2, 3]) -- [1, 2, 3, 1, 2]
- repeat
-
ひとつの要素を無限に繰り返すリストを返す
take 5 (repeat 'Z') -- "ZZZZZ"
putStrLn (take 4 (repeat 'あ')) -- 「ああああ」と出力する - replicate
-
ひとつの要素を指定回数繰り返すリストを返す
putStrLn (replicate 4 'あ') -- 「ああああ」と出力
replicate 5 7 -- [7, 7, 7, 7, 7]
範囲でリストを作成
例えば1から1000までのリストを作りたい時に[1, 2, 3, 4, 5, ......... 1000]って 書くのは大変ですが、リストを範囲で指定できます。
[1..1000] -- 1から1000までのリスト
[10, 20..1000] -- 10から10ずつ増加で1000まで [10, 20, 30, 40 ....]
[10, 20..] -- 10から10ずつ増加の無限リストtakeなどと組み合わせて使うと便利
pythonでは
range(1, 10) # 1, 2, 3, 4, 5, 6, 7, 8, 9
range(10, 1001, 10) # 10から10ずつ増加で1000まで [10, 20, 30, 40 ....]
と、第二引数より小さい値でリストを作成しますが、Haskellでは書いた値を含む リストを作るのでpythonプログラマーは注意が必要ですね。
リストの内包的表記
1000までのリストも簡単に作れる事がわかりました。今度は1000までの3か5の倍数をリストにしたいとします。
[3, 5, 6, 9, 10, 12, 15, 18 ...... ]
ってやらなくちゃならなくなります。 数学では、これを集合の内包的記法という表現方法で表します。(らしいです)
{x|1 <= x <= 1000 かつ xは3か5の倍数}
みたいな感じらしいです。
たしかにこうすれば、ややこしいリストが必要な場合でもわりと簡単に作成する事ができますね。 Haskellではこれを再現できるようです。
[x | x <- [1..1000], x `mod` 3 == 0 || x `mod` 5 == 0]
と表現します。
ちなみにpythonでは
[x for x in range(1, 1001) if x % 3 == 0 or x % 5 == 0]
と書けます。
で、この3と5の倍数の各要素を7倍したリストというのも作れます。
[x * 7 | x <- [1..1000], x `mod` 3 == 0 || x `mod` 5 == 0]
となります。
pythonでも同じように
[x * 7 for x in range(1, 1001) if x % 3 == 0 or x % 5 == 0]
とすれば同じリストを作成する事ができます。
本体価格のリストから消費税8%込のリストを作ってみました。
[round (price * 1.08) | price <- [1000, 1200, 900, 560, 480]]
次回、タプルを勉強してみたいと思います。
| 固定リンク
「Haskell」カテゴリの記事
- タプルとはなんだろうか? - Haskell(2018.07.20)
- 関数呼び出し、リスト、内包表記 -- Haskell(2018.07.08)
- ”すごいHaskellたのしく学ぼう!”でHaskellを始めてみようと思います(2018.07.05)
この記事へのコメントは終了しました。
コメント