Haskell 入門 #2 | NANOG

Haskell 入門 #2

Wataru "Alt" Ohgai <alt@jj1lfc.dev>

2023/11/11 NANOG 言語勉強会

Haskell 入門 #2 | NANOG

前書き

本講は Haskell 初心者の Alt が教科書で学んだ内容をアウトプットするものです.
英語版原著を基に最新の情報を交えながら日本語で進めていきます.

教科書・参考・出典

クレジット

作成者: Alt <alt@jj1lfc.dev>
Special Thanks:

ライセンス: CC BY-NC-SA 3.0 Deed

Haskell 入門 #2 | NANOG

Starting Out

Ready, set, go!

GHCi で四則演算

ghci> 2 + 15
ghci> 49 * 100
ghci> 1892 - 1472
ghci> 5 / 2
ghci> (50 * 100) - 4999
ghci> 50 * 100 - 4999
ghci> 50 * (100 - 4999)
Haskell 入門 #2 | NANOG

GHCi で論理演算

ghci> True && False  -- && は AND 演算
ghci> True && True
ghci> False || True  -- || は OR 演算
ghci> not False
ghci> not (True && True)
ghci> 5 == 5
ghci> 1 == 0
ghci> 5 /= 5
ghci> 5 /= 4
ghci> "hello" == "hello"
ghci> 5 == True  -- 型エラーになる
ghci> 5 + 4.0  -- 5 が float と評価される
Haskell 入門 #2 | NANOG

infix 関数と prefix 関数

  • infix 関数: 四則演算・論理演算等で使った,引数に挟んで使う関数
  • prefix 関数: 関数名 引数1 引数2 ... の形で使うオーソドックスな関数
ghci> succ 8
ghci> min 9 10
ghci> min 3.4 3.2
ghci> max 100 101
ghci> succ 9 + max 5 4 + 1
ghci> (succ 9) + (max 5 4) + 1
ghci> div 92 10
ghci> 92 `div` 10

Q: bar (bar 3) の意味は?

他言語: 第 1 引数を bar 第 2 引数を 3 として bar 関数を呼んでいる

Haskell: 引数を 3 とする bar 関数を引数として bar 関数を呼んでいる

他言語と関数/引数の書き方が大きく違う

Haskell 入門 #2 | NANOG

Baby's first functions

引数を 2 倍する関数 doubleMe を作る

練習環境02/baby.hs を開く

doubleMe x = x + x

GHCi にロード・実行

ghci> :l 02/baby  -- baby.hs をロードする
ghci> doubleMe 9  -- Int でも動く
ghci> doubleMe 8.3  -- Float でも動く
Haskell 入門 #2 | NANOG

複数の引数をそれぞれ 2 倍する関数 doubleUs を作る

02/baby.hs

doubleUs x y = x*2 + y*2

ロードして実行

ghci> doubleUs 4 9
ghci> doubleUs 2.3 34.2
ghci> doubleUs 28 88 + doubleMe 123
Haskell 入門 #2 | NANOG

関数で関数を作る

02/baby.hs

doubleUs x y = doubleMe x + doubleMe y -- コメントアウトされているのを入れ替える

ロードして実行 → 同じ値が得られる

ghci> doubleUs 4 9
ghci> doubleUs 2.3 34.2
ghci> doubleUs 28 88 + doubleMe 123

Haskell では簡単な関数を組み合わせて難しい関数を作ることが多い.

Haskell 入門 #2 | NANOG

引数が 100 以下の場合にのみ 2 倍して返す関数を作る

02/baby.hs

doubleSmallNumber x = if x > 100
                        then x
                        else x*2

Haskell における if 文

  • if 文は expression <expr> である
    • expression: 必ず返値を返す関数
  • if 文には else が必要である
Haskell 入門 #2 | NANOG

doubleSmallNumber 関数に 1 を足す関数を作る

02/baby.hs

doubleSmallNumber' x = (if x > 100 then x else x*2) + 1
  • 一行でも記述可能
  • ' も関数名の一部として使用可能

02/baby.hs

conanO'Brien = "It's a-me, Conan O'Brien!"
  • conanO'Brien: 関数名は小文字から
  • 引数を取らない関数: definition である
Haskell 入門 #2 | NANOG

An intro to lists

※本章は全て GHCi での作業

ghci> lostNumbers = [4,8,15,16,23,42]
ghci> lostNumbers
  • 一つの List では同一の型しかメンバになれない
  • String 型は Char 型のリスト
Haskell 入門 #2 | NANOG

List の結合

[List] ++ [List2] で結合できる

ghci> [1,2,3,4] ++ [9,10,11,12]
ghci> "hello" ++ " " ++ "world"
ghci> ['w','o'] ++ ['o','t']
  • ++ は左辺の最初のメンバから順に読んでいき List を作る関数
    • → 長い List に適用すると処理に時間がかかる
Haskell 入門 #2 | NANOG

List への追加

なにか:[List] で List にメンバを追加できる

ghci> 'A':" SMALL CAT"
ghci> 5:[1,2,3,4,5]
  • 一つの Char と List を読むだけですむ

[1,2,3] の正体は 1:2:3:[]← 後々解説します

Haskell 入門 #2 | NANOG

List から特定のメンバを読み出す

[List] !! index で読み出せる

ghci> "Steve Buscemi" !! 6
ghci> [9.4,33.2,96.2,11.2,23.25] !! 1
  • List にはインデックスがある
  • インデックスの範囲外のメンバを呼ぼうとするとエラー
Haskell 入門 #2 | NANOG

List の入れ子

ghci> b = [[1,2,3,4],[5,3,3,3],[1,2,2,3,4],[1,2,3]]
ghci> b
ghci> b ++ [[1,1,1,1]]
ghci> [6,6,6]:b
ghci> b !! 2
  • List は入れ子にできる
  • 異なる長さの List も入れ子にできるが,異なる型の List は入れ子にできない
Haskell 入門 #2 | NANOG

List の比較演算

List は <, <=, ==, >=, > を用いて比較演算できる

ghci> [3,2,1] > [2,1,0]
ghci> [3,2,1] > [2,10,100]
ghci> [3,4,2] > [3,4]
ghci> [3,4,2] > [2,4]
ghci> [3,4,2] == [3,4,2]
  • リストのメンバ同士を左から順に比較評価している
  • False な場合 2 つめ同士を評価...
Haskell 入門 #2 | NANOG

List で使う主要な関数

ghci> head [5,4,3,2,1]
ghci> tail [5,4,3,2,1]
ghci> last [5,4,3,2,1]
ghci> init [5,4,3,2,1]
  • これらは空の List には使用できない (エラーになる)
  • このエラーはコンパイル時にキャッチされない

※図は教科書より

Haskell 入門 #2 | NANOG

List で使う主要な関数 2

ghci> length [5,4,3,2,1]
ghci> null [1,2,3]
ghci> 4 `elem` [3,4,5,6]
ghci> reverse [5,4,3,2,1]
ghci> maximum [1,9,2,3,4]
ghci> minimum [8,4,2,1,5,6]
ghci> sum [5,2,1,6,3,2,5,7]
ghci> product [6,2,1,2]
ghci> take 3 [5,4,3,2,1]
ghci> take 5 [1,2]
ghci> take 0 [6,6,6]
ghci> drop 3 [8,4,2,1,5,6]
ghci> drop 0 [1,2,3,4]
ghci> drop 100 [1,2,3,4]