(2008.8.18 新規作成。)
操作と言っても、Haskell のオブジェクトは immutable なので、関数がリストを返す場合、それは新しいリストです。
Haskell は lazy evaluation ですから、例えば、木構造のデータをリストに変換して、リストとして操作するようにプログラムを書いたりしても, 実際に必要な部分しか評価されませんから, 効率の問題はありません。
●TODO: リストの例を追加する。
map :: (a -> b) -> [a] -> [b] -- Defined in `GHC.Base'
Prelude> map (* 2) [1, 2, 3] [2,4,6]
●擬似コード?? map f [x1, x2, ...] == [f x1, f x2, ...]
リストの内包記法で次のように書くのと同じ。
filter p xs = [ x | x <- xs, p x]
head :: [a] -> a
n 個の要素を取り出すときは take を使う。
tail :: [a] -> [a]
(!!) :: [a] -> Int -> a
takeWhile (< 3) [1,2,3,4,1,2,3,4] == [1,2]
dropWhile (< 3) [1,2,3,4,5,1,2,3] == [3,4,5,1,2,3]
elem :: Eq a => a -> [a] -> Bool -- Defined in `GHC.List' infix 4 `elem`
elem 1 [1,2,3] -- True elem 1 [2,3,4] -- False
中置きで書くこともできます。
Prelude> 5 `elem` [1,2,3] False
次と同じ。
elem x xs = any (== x) xs notElem x xs = all (/= x) xs
Prelude> Data.List.find (== 1) [1, 2, 3] Just 1 Prelude> Data.List.find (== 3) [2, 4, 6] Nothing
リストに関数を適用し、集約します。
foldl
で次のように書くのと同じです。
sum xs = foldl (+) 0 xs
product xs = foldl (*) 1 xs
汎用の畳み込み演算として、foldl
, foldr
があります。
Wikipedia の図がイメージしやすいと思います。Fold (higher-order function) - Wikipedia, the free encyclopedia
Rubyだと、Enumerable#inject()
-- 別名 Enumerable#reduce()
-- が foldl
に相当します。inject()
に引数を渡さなければ foldl1
になります。
[1,2.3].inject(10) {|prev, item| prev - item} #=> 10 - 1 - 2 - 3 = 4
ややマニアックな解説は、例えば、
foldl :: (a -> b -> a) -> a -> [b] -> a -- Defined in `GHC.List'
foldl (-) 1 [2, 3, 4] = ((1 - 2) - 3) - 4 == -8定義は次のようになっています。
foldl f z [] = z foldl f z (x:xs) = foldl f (f z x) xs
定義はこうです。
foldr f z [] = z foldr f z (x:xs) = f x (foldr f z xs)
foldl1 f (x:xs) = foldl f x xs foldl1 _ [] = errorEmptyList "foldl1"
foldr1 _ [x] = x foldr1 f (x:xs) = f x (foldr1 f xs) foldr1 _ [] = errorEmptyList "foldr1"