Haskell 入門 #3 | NANOG

Haskell 入門 #3

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

2023/11/18 NANOG 言語勉強会

Haskell 入門 #3 | NANOG

前書き

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

教科書・参考・出典

クレジット

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

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

Haskell 入門 #3 | NANOG

Starting Out

Texas ranges

[始点]から[終点]までの範囲のリスト

ghci> [1..20]
ghci> ['a'..'z']
ghci> ['K'..'Z']

間隔 (ステップ) も定義できる

ghci> [2,4..20]
ghci> [3,6..20]
ghci> [20,19..1]

最初の 2 つで規則性を示す必要があるため等差数列のみこの方法で表現可能

Haskell 入門 #3 | NANOG

Float でもできるのか...?

ghci> [0.1, 0.3 .. 1]

やめた方がよさそう

13 ずつ増える等差数列の最初の 24 項

ghci> [13,26..13*24]
ghci> take 24 [13,26..]

※無限リストを扱う際はスライスするまで評価されない

Haskell 入門 #3 | NANOG

無限リスト関連の主要な関数

ghci> take 10 (cycle [1,2,3])
ghci> take 12 (cycle "LOL ")
ghci> take 10 (repeat 5) -- replicate 5 10 の方がわかりやすいが
Haskell 入門 #3 | NANOG

I'm a list comprehension

x[1..10] のとき x*2 で表される数列

ghci> [x*2 | x <- [1..10]]

上記のうち x*2 >= 12 を満たす数列

ghci> [x*2 | x <- [1..10], x*2 >= 12]  -- カンマ以降をはフィルタ

[50..100] のうち,7 で割った余りが 3 になる数列

ghci> [x | x <- [50..100], x `mod` 7 == 3]
Haskell 入門 #3 | NANOG

リスト内の 10 より大きい奇数を "BANG!" に置き換え,10 より小さい奇数を "BOOM!" に置き換え,偶数は捨てる関数 boomBangs
03/list-comprehension.hs

boomBangs xs = [ if x < 10 then "BOOM!" else "BANG!" | x <- xs, odd x]
ghci> boomBangs [7..13]

[10..20] のうち 13, 15, 19 を含まない数列

ghci> [ x | x <- [10..20], x /= 13, x /= 15, x /= 19]
Haskell 入門 #3 | NANOG

複数のリストの組み合わせ

[2,5,10][8,10,11] をそれぞれ掛け合わせたい

ghci> [ x*y | x <- [2,5,10], y <- [8,10,11]]

このうち 50 より大きいものだけ

ghci> [ x*y | x <- [2,5,10], y <- [8,10,11], x*y > 50]
Haskell 入門 #3 | NANOG

length 関数を length' として自分で作ってみる

03/list-comprehension.hs

length' xs = sum [1 | _ <- xs]

_ は全てのパターンにマッチする表現
List xs の要素全てを 1 に書き換えて積算している

Haskell 入門 #3 | NANOG

文字列から大文字のみを抜き出す関数 removeNonUppercase

03/list-comprehension.hs

removeNonUppercase st = [ c | c <- st, c `elem` ['A'..'Z']]
ghci> removeNonUppercase "Hahaha! Ahahaha!"
ghci> removeNonUppercase "IdontLIKEFROGS"
Haskell 入門 #3 | NANOG

List を含む List から奇数を全て除く (偶数だけを抜き出す) 関数

ghci> 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]]
ghci> [ [ x | x <- xs, even x ] | xs <- xxs]
Haskell 入門 #3 | NANOG

Tuples

List と Tuple の主な違い

List

  • 要素は全て同一の型
  • 型は要素の型に依存する
  • 要素の数は気にしなくて良い
    (0 から無限)
  • [cmp1,cmp2] で表現

Tuple

  • 要素の型は同一でなくても良い
  • 型は要素の数と型に依存する
  • 要素の数を指定する必要がある
    (有限個)
  • (cmp1,cmp2) で表現
Haskell 入門 #3 | NANOG

平面におけるベクトル (二次元ベクトル) を Haskell で表現したい

  • List を使って表現可能 [[1,2],[8,11],[4,5]]
  • [[1,2],[8,11,5],[4,5]] は?
    • Haskell 的には問題ないが,二次元ベクトルではなくなってしまう

→ サイズ 2 の Tuple (pair) を要素とする List とする

  • [(1,2),(8,11),(4,5)] → Haskell で表現できた
  • [(1,2),(8,11,5),(4,5)] → Haskell 的にエラー
    • List は同一の型しか持てない
    • (1,2) :: (Num a, Num b) => (a,b)
    • (8,11,5) :: (Num a, Num b, Num c) => (a,b,c)
    • [(1,2),(8,11),(4,5)] :: (Num a, Num b) => [(a, b)]
Haskell 入門 #3 | NANOG

Tuple 関連の主要な関数

ghci> fst (8,11) -- pair にのみ使用可
ghci> snd (8,11) -- pair にのみ使用可
ghci> zip [1,2,3,4,5] [5,5,5,5,5]
ghci> zip [1 .. 5] ["one", "two", "three", "four", "five"]
ghci> zip [5,3,2,6,2,7,2,5,4,6,6] ["im","a","turtle"]
ghci> zip [1..] ["apple", "orange", "cherry", "mango"]
Haskell 入門 #3 | NANOG

Tuple と List を使う問題

各辺の長さがそれぞれ 10 以下の整数で,周が 24 になる直角三角形を求めよ

-- まずは各辺の長さがそれぞれ 10 以下の整数である三角形を考える
ghci> triangles = [ (a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10] ]
-- 直角三角形のみに絞る
-- 辺 b は斜辺 c 以下であり,辺 a は辺 b 以下である
-- ピタゴラスの定理
ghci> rightTriangles = [ (a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2]
-- 周が 24 のものに絞る
ghci> rightTriangles' = [ (a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2, a+b+c == 24]