Haskell Language
リスト
サーチ…
構文
空のリストコンストラクタ
[] :: [a]
空でないリストコンストラクタ
(:) :: a -> [a] -> [a]
head - リストの最初の値を返す
head :: [a] -> a
last - リストの最後の値を返す
last :: [a] -> a
tail - 最初の項目のないリストを返す
tail :: [a] -> [a]
init - 最後の項目がないリストを返す
init :: [a] -> [a]
xs !! i - リストxsのインデックスiで要素を返す
(!!) :: Int -> [a] -> a
take n xs - リストの最初のn個の要素を含む新しいリストを返すxs
take :: Int -> [a] -> [a]
map ::(a - > b) - > [a] - > [b]
filter ::(a - > Bool) - > [a] - > [a]
(++):: [a] - > [a]
concat :: [[a]] - > [a]
備考
- 型
[a]
は[] a
と等価です。 -
[]
空のリストを作成します。 -
[]
関数定義LHSで、例えばf [] = ...
、空のリストパターンです。 -
x:xs
は、要素x
がリストの先頭に追加されたリストを作成しますxs
-
f (x:xs) = ...
は空でないリストのパターンマッチで、x
は頭、xs
はテールです。 -
f (a:b:cs) = ...
とf (a:(b:cs)) = ...
は同じです。それらは、最初の要素がa
であり、2番目の要素がb
であり、リストの残りがcs
である少なくとも2つの要素のリストのパターン一致です。 -
f ((a:as):bs) = ...
はf (a:(as:bs)) = ...
と同じではありません。前者はリストの非空リスト、用のパターンマッチで、ヘッドのヘッドであるa
as
ヘッドの尾部であり、bs
尾です。 -
f (x:[]) = ...
とf [x] = ...
は同じです。これらは正確に1つの要素のリストのパターンマッチです。 -
f (a:b:[]) = ...
とf [a,b] = ...
は同じです。これらは正確に2つの要素のリストのパターンマッチです。 -
f [a:b] = ...
は、要素がリストでもある正確に1つの要素のリストのパターンマッチです。a
は要素の先頭、b
は要素の末尾です。 -
[a,b,c]
は(a:b:c:[])
と同じです。標準リスト表記法は、(:)
と[]
コンストラクタの文法的な砂糖です。 - もう一度
(x:y:ys)
を繰り返す代わりに、リスト全体をall
(または選択した他の名前)として参照するために、all@(x:y:ys)
をall@(x:y:ys)
使用することができます。
リストリテラル
emptyList = []
singletonList = [0] -- = 0 : []
listOfNums = [1, 2, 3] -- = 1 : 2 : [3]
listOfStrings = ["A", "B", "C"]
リストの連結
listA = [1, 2, 3]
listB = [4, 5, 6]
listAThenB = listA ++ listB -- [1, 2, 3, 4, 5, 6]
(++) xs [] = xs
(++) [] ys = ys
(++) (x:xs) ys = x : (xs ++ ys)
リストの基礎
Haskell Preludeのリストの型コンストラクタは[]
です。 Int
型の値を保持するリストの型宣言は、次のように記述されます。
xs :: [Int] -- or equivalently, but less conveniently,
xs :: [] Int
Haskellのリストは同質の系列です。つまり、すべての要素が同じ型でなければなりません。タプルとは異なり、リストタイプは長さの影響を受けません:
[1,2,3] :: [Int]
[1,2,3,4] :: [Int]
[]
は空のリストを作成します。(:)
、 "cons"と発音され、要素をリストの前に付加します。コンスのx
(タイプの値a
上に)、xs
(同じタイプの値のリストa
)、そのヘッド (第1要素)である新しいリスト作成x
、及び尾部 (残りの要素)であるxs
。
以下のような簡単なリストを定義することができます:
ys :: [a]
ys = []
xs :: [Int]
xs = 12 : (99 : (37 : []))
-- or = 12 : 99 : 37 : [] -- ((:) is right-associative)
-- or = [12, 99, 37] -- (syntactic sugar for lists)
リストの作成に使用できる(++)
、 (:)
と[]
観点から再帰的に定義されています。
リストの処理
リストを処理するには、単純にリスト型のコンストラクタのパターンマッチングを行うことができます:
listSum :: [Int] -> Int
listSum [] = 0
listSum (x:xs) = x + listSum xs
もっと複雑なパターンを指定することで、より多くの値を一致させることができます。
sumTwoPer :: [Int] -> Int
sumTwoPer [] = 0
sumTwoPer (x1:x2:xs) = x1 + x2 + sumTwoPer xs
sumTwoPer (x:xs) = x + sumTwoPer xs
上記の例では、奇数長のリストが引数として指定されたケースを処理するために、より網羅的なパターンマッチングを提供する必要がありました。
Haskell Preludeは、 map
、 filter
などのリストを扱うための多くの組み込み関数を定義しています。可能であれば、独自の再帰関数を記述するのではなく、これらを使うべきです。
リストの要素へのアクセス
リストのn番目の要素にアクセスする(ゼロから始まる):
list = [1 .. 10]
firstElement = list !! 0 -- 1
注意してください!!
部分的な関数なので、特定の入力はエラーを生成します:
list !! (-1) -- *** Exception: Prelude.!!: negative index
list !! 1000 -- *** Exception: Prelude.!!: index too large
Data.List.genericIndex
もあります!!
Integral
値をインデックスとして受け取ります。
import Data.List (genericIndex)
list `genericIndex` 4 -- 5
単一リンクリストとして実装された場合、これらの操作はO(n)時間かかる。インデックスで頻繁に要素にアクセスする場合は、( ベクトルパッケージの) Data.Vector
やその他のデータ構造を使用する方がよいでしょう。
レンジ
1から10までのリストを作成するには、範囲表記法を使用するのが簡単です。
[1..10] -- [1,2,3,4,5,6,7,8,9,10]
ステップを指定するには、コンマと次の要素をstart要素の後に追加します。
[1,3..10] -- [1,3,5,7,9]
ハスケルは常にステップ間の算術的な違いとしてステップをとり、最初の2つ以上の要素と上限を指定することはできないことに注意してください。
[1,3,5..10] -- error
[1,3,9..20] -- error
範囲を降順で生成するには、常に負のステップを指定します。
[5..1] -- []
[5,4..1] -- [5,4,3,2,1]
Haskellは厳密ではないので、リストの要素は必要な場合にのみ評価され、無限リストを使うことができます。 [1..]
は[1..]
から始まる無限のリストです。このリストは変数にバインドすることも、関数の引数として渡すこともできます。
take 5 [1..] -- returns [1,2,3,4,5] even though [1..] is infinite
丸めの問題を回避するために、浮動小数点値を含む範囲を使用するときは、最大で半分の差分を受け入れるため注意が必要です。
[1.0,1.5..2.4] -- [1.0,1.5,2.0,2.5] , though 2.5 > 2.4
[1.0,1.1..1.2] -- [1.0,1.1,1.2000000000000002] , though 1.2000000000000002 > 1.2
範囲は数値だけでなく、 Enum
型の型クラスを実装するすべての型で機能します。いくつかの列挙可能な変数a
、 b
、 c
と、範囲構文はこれらのEnum
メソッドを呼び出すのと同じです。
[a..] == enumFrom a
[a..c] == enumFromTo a c
[a,b..] == enumFromThen a b
[a,b..c] == enumFromThenTo a b c
たとえば、 Bool
では
[False ..] -- [False,True]
False
後にスペースがあることに注意して、これがモジュール名の修飾として解析されないようにしてください( False..
はモジュールFalse
から解析され.
)。
リストの基本機能
head [1..10] -- 1
last [1..20] -- 20
tail [1..5] -- [2, 3, 4, 5]
init [1..5] -- [1, 2, 3, 4]
length [1 .. 10] -- 10
reverse [1 .. 10] -- [10, 9 .. 1]
take 5 [1, 2 .. ] -- [1, 2, 3, 4, 5]
drop 5 [1 .. 10] -- [6, 7, 8, 9, 10]
concat [[1,2], [], [4]] -- [1,2,4]
折りたたみ
これは、左折がどのように実装されているかです。 step関数の引数の順序がfoldr
(右折)と比べてどのように反転しているかに注目してください。
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f acc [] = acc
foldl f acc (x:xs) = foldl f (f acc x) xs -- = foldl f (acc `f` x) xs
左の折りたたみfoldl
は左に関連付けられます。あれは:
foldl (+) 0 [1, 2, 3] -- is equivalent to ((0 + 1) + 2) + 3
理由は、 foldl
は次のように評価される( foldl
の帰納的ステップを参照)。
foldl (+) 0 [1, 2, 3] -- foldl (+) 0 [ 1, 2, 3 ]
foldl (+) ((+) 0 1) [2, 3] -- foldl (+) (0 + 1) [ 2, 3 ]
foldl (+) ((+) ((+) 0 1) 2) [3] -- foldl (+) ((0 + 1) + 2) [ 3 ]
foldl (+) ((+) ((+) ((+) 0 1) 2) 3) [] -- foldl (+) (((0 + 1) + 2) + 3) []
((+) ((+) ((+) 0 1) 2) 3) -- (((0 + 1) + 2) + 3)
最後の行は、 ((0 + 1) + 2) + 3
と等価です。これは、 (fab)
が一般的に(a `f` b)
(fab)
と同じであり、したがって((+) 0 1)
が特に(0 + 1)
と同じであるためです。
折りたたみ
これは、右折がどのように実装されるかです:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs) -- = x `f` foldr f z xs
右の折りたたみfoldr
は右に関連付けられます。あれは:
foldr (+) 0 [1, 2, 3] -- is equivalent to 1 + (2 + (3 + 0))
理由はfoldr
が次のように評価されるからです( foldr
誘導ステップを見てください)。
foldr (+) 0 [1, 2, 3] -- foldr (+) 0 [1,2,3]
(+) 1 (foldr (+) 0 [2, 3]) -- 1 + foldr (+) 0 [2,3]
(+) 1 ((+) 2 (foldr (+) 0 [3])) -- 1 + (2 + foldr (+) 0 [3])
(+) 1 ((+) 2 ((+) 3 (foldr (+) 0 []))) -- 1 + (2 + (3 + foldr (+) 0 []))
(+) 1 ((+) 2 ((+) 3 0)) -- 1 + (2 + (3 + 0 ))
最後の行は、 ((+) 3 0)
が(3 + 0)
と同じであるため、 1 + (2 + (3 + 0))
に相当します。
`map`を使った変換
しばしば、コレクションの内容(リスト、またはトラバース可能なもの)を変換または変換することを望みます。ハスケルではmap
を使用しmap
:
-- Simple add 1
map (+ 1) [1,2,3]
[2,3,4]
map odd [1,2,3]
[True,False,True]
data Gender = Male | Female deriving Show
data Person = Person String Gender Int deriving Show
-- Extract just the age from a list of people
map (\(Person n g a) -> a) [(Person "Alex" Male 31),(Person "Ellie" Female 29)]
[31,29]
`filter`によるフィルタリング
与えられたリスト:
li = [1,2,3,4,5]
filter ::( filter :: (a -> Bool) -> [a] -> [a]
を使用して述語でリストをフィルタリングできます。
filter (== 1) li -- [1]
filter (even) li -- [2,4]
filter (odd) li -- [1,3,5]
-- Something slightly more complicated
comfy i = notTooLarge && isEven
where
notTooLarge = (i + 1) < 5
isEven = even i
filter comfy li -- [2]
もちろん、数字だけではありません。
data Gender = Male | Female deriving Show
data Person = Person String Gender Int deriving Show
onlyLadies :: [Person] -> Person
onlyLadies x = filter isFemale x
where
isFemale (Person _ Female _) = True
isFemale _ = False
onlyLadies [(Person "Alex" Male 31),(Person "Ellie" Female 29)]
-- [Person "Ellie" Female 29]
リストの圧縮と解凍
zipは2つのリストを取り、対応するペアのリストを返します。
zip [] _ = []
zip _ [] = []
zip (a:as) (b:bs) = (a,b) : zip as bs
> zip [1,3,5] [2,4,6]
> [(1,2),(3,4),(5,6)]
関数で2つのリストを圧縮する:
zipWith f [] _ = []
zipWith f _ [] = []
zipWith f (a:as) (b:bs) = f a b : zipWith f as bs
> zipWith (+) [1,3,5] [2,4,6]
> [3,7,11]
リストの解凍:
unzip = foldr (\(a,b) ~(as,bs) -> (a:as,b:bs)) ([],[])
> unzip [(1,2),(3,4),(5,6)]
> ([1,3,5],[2,4,6])