Data.List

Data.List

Data.List 모듈은 리스트 조작에 필요한 기본 함수들을 제공해요.

출처: Haskell 2010 언어 리포트

본문

20.1 기본 함수 (Basic functions)

(++) :: [a] -> [a] -> [a]

두 리스트를 이어붙여요. 즉,

[x1, ..., xm] ++ [y1, ..., yn]  ==  [x1, ..., xm, y1, ..., yn]
[x1, ..., xm] ++ [y1, ...]      ==  [x1, ..., xm, y1, ...]

첫 번째 리스트가 유한하지 않으면 결괏값은 첫 번째 리스트예요.

head :: [a] -> a

리스트의 첫 번째 요소를 추출해요. 리스트는 비어 있지 않아야 해요.

last :: [a] -> a

리스트의 마지막 요소를 추출해요. 리스트는 유한하고 비어 있지 않아야 해요.

tail :: [a] -> [a]

리스트에서 head 뒤의 요소들을 추출해요. 리스트는 비어 있지 않아야 해요.

init :: [a] -> [a]

리스트에서 마지막 요소를 뺀 나머지 모든 요소를 돌려줘요. 리스트는 비어 있지 않아야 해요.

null :: [a] -> Bool

리스트가 비어 있는지 검사해요.

length :: [a] -> Int

O(n). length는 유한 리스트의 길이를 Int로 돌려줘요. 이는 결괏값 타입이 어떤 숫자 종류든 될 수 있는 더 일반적인 Data.List.genericLength의 한 인스턴스예요.

20.2 리스트 변환 (List transformations)

map :: (a -> b) -> [a] -> [b]

map f xsfxs의 각 요소에 적용해 얻은 리스트예요. 즉,

map f [x1, x2, ..., xn]  ==  [f x1, f x2, ..., f xn]
map f [x1, x2, ...]      ==  [f x1, f x2, ...]
reverse :: [a] -> [a]

reverse xsxs의 요소들을 역순으로 돌려줘요. xs는 유한해야 해요.

intersperse :: a -> [a] -> [a]

intersperse 함수는 요소와 리스트를 받아 리스트의 요소들 사이에 그 요소를 '사이사이에 넣어요(intersperses)'. 예를 들어,

intersperse ',' "abcde"  ==  "a,b,c,d,e"
intercalate :: [a] -> [[a]] -> [a]

intercalate xs xss(concat (intersperse xs xss))와 동등해요. 리스트 xsxss의 리스트들 사이에 끼워 넣고 결과를 이어붙여요.

transpose :: [[a]] -> [[a]]

transpose 함수는 인자의 행과 열을 바꿔요. 예를 들어,

transpose [[1,2,3],[4,5,6]]  ==  [[1,4],[2,5],[3,6]]
subsequences :: [a] -> [[a]]

subsequences 함수는 인자의 모든 부분 수열(subsequence)의 리스트를 돌려줘요.

subsequences "abc"  ==  ["","a","b","ab","c","ac","bc","abc"]
permutations :: [a] -> [[a]]

permutations 함수는 인자의 모든 순열(permutation)의 리스트를 돌려줘요.

permutations "abc"  ==  ["abc","bac","cba","bca","cab","acb"]

20.3 리스트 축소 (Reducing lists; folds)

foldl :: (a -> b -> a) -> a -> [b] -> a

foldl은 이항 연산자, 시작 값(보통 연산자의 왼쪽 항등원), 그리고 리스트에 적용되어 이항 연산자로 리스트를 왼쪽에서 오른쪽으로 축소해요:

foldl f z [x1, x2, ..., xn]  ==  (...((z `f` x1) `f` x2) `f`...) `f` xn

리스트는 유한해야 해요.

foldl' :: (a -> b -> a) -> a -> [b] -> a

foldl의 엄격(strict) 버전이에요.

foldl1 :: (a -> a -> a) -> [a] -> a

foldl1은 시작 값 인자가 없는 foldl의 변형이라 반드시 비어 있지 않은 리스트에 적용되어야 해요.

foldl1' :: (a -> a -> a) -> [a] -> a

foldl1의 엄격 버전이에요.

foldr :: (a -> b -> b) -> b -> [a] -> b

foldr은 이항 연산자, 시작 값(보통 연산자의 오른쪽 항등원), 그리고 리스트에 적용되어 이항 연산자로 리스트를 오른쪽에서 왼쪽으로 축소해요:

foldr f z [x1, x2, ..., xn]  ==  x1 `f` (x2 `f` ... (xn `f` z)...)
foldr1 :: (a -> a -> a) -> [a] -> a

foldr1은 시작 값 인자가 없는 foldr의 변형이라 반드시 비어 있지 않은 리스트에 적용되어야 해요.

특수 접기 (Special folds)

concat :: [[a]] -> [a]

리스트의 리스트를 이어붙여요.

concatMap :: (a -> [b]) -> [a] -> [b]

함수를 리스트에 매핑하고 결과를 이어붙여요.

and :: [Bool] -> Bool

and는 부울 리스트의 논리곱(conjunction)을 돌려줘요. 결과가 True가 되려면 리스트가 유한해야 하고, False는 유한하거나 무한한 리스트의 유한 인덱스에 있는 False 값에서 나와요.

or :: [Bool] -> Bool

or는 부울 리스트의 논리합(disjunction)을 돌려줘요. 결과가 False가 되려면 리스트가 유한해야 하고, True는 유한하거나 무한한 리스트의 유한 인덱스에 있는 True 값에서 나와요.

any :: (a -> Bool) -> [a] -> Bool

술어와 리스트에 적용되어, any는 리스트의 어떤 요소가 술어를 만족하는지 판정해요. 결과가 False가 되려면 리스트가 유한해야 하고, True는 유한하거나 무한한 리스트의 유한 인덱스에 있는 요소에 술어를 적용한 값이 True일 때 나와요.

all :: (a -> Bool) -> [a] -> Bool

술어와 리스트에 적용되어, all은 리스트의 모든 요소가 술어를 만족하는지 판정해요. 결과가 True가 되려면 리스트가 유한해야 하고, False는 유한하거나 무한한 리스트의 유한 인덱스에 있는 요소에 술어를 적용한 값이 False일 때 나와요.

sum :: Num a => [a] -> a

sum 함수는 유한한 숫자 리스트의 합을 계산해요.

product :: Num a => [a] -> a

product 함수는 유한한 숫자 리스트의 곱을 계산해요.

maximum :: Ord a => [a] -> a

maximum은 리스트에서 최댓값을 돌려줘요. 리스트는 비어 있지 않고 유한하며 정렬 가능한(ordered) 타입이어야 해요. 이것은 프로그래머가 자신의 비교 함수를 제공할 수 있는 maximumBy의 특수한 경우예요.

minimum :: Ord a => [a] -> a

minimum은 리스트에서 최솟값을 돌려줘요. 리스트는 비어 있지 않고 유한하며 정렬 가능한 타입이어야 해요. 이것은 프로그래머가 자신의 비교 함수를 제공할 수 있는 minimumBy의 특수한 경우예요.

20.4 리스트 만들기 (Building lists)

스캔 (Scans)

scanl :: (a -> b -> a) -> a -> [b] -> [a]

scanlfoldl과 비슷하지만 왼쪽에서 연속적인 축소 값들의 리스트를 돌려줘요:

scanl f z [x1, x2, ...]  ==  [z, z `f` x1, (z `f` x1) `f` x2, ...]

last (scanl f z xs) == foldl f z xs라는 점을 유의하세요.

scanl1 :: (a -> a -> a) -> [a] -> [a]

scanl1은 시작 값 인자가 없는 scanl의 변형이에요:

scanl1 f [x1, x2, ...]  ==  [x1, x1 `f` x2, ...]
scanr :: (a -> b -> b) -> b -> [a] -> [b]

scanrscanl의 오른쪽에서 왼쪽으로 가는 쌍대(dual)예요. head (scanr f z xs) == foldr f z xs라는 점을 유의하세요.

scanr1 :: (a -> a -> a) -> [a] -> [a]

scanr1은 시작 값 인자가 없는 scanr의 변형이에요.

누적 맵 (Accumulating maps)

mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])

mapAccumL 함수는 mapfoldl의 결합처럼 동작해요. 리스트의 각 요소에 함수를 적용하되 누적 매개변수(accumulating parameter)를 왼쪽에서 오른쪽으로 전달하고, 누적자의 최종 값과 함께 새 리스트를 돌려줘요.

mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])

mapAccumR 함수는 mapfoldr의 결합처럼 동작해요. 리스트의 각 요소에 함수를 적용하되 누적 매개변수를 오른쪽에서 왼쪽으로 전달하고, 누적자의 최종 값과 함께 새 리스트를 돌려줘요.

무한 리스트 (Infinite lists)

iterate :: (a -> a) -> a -> [a]

iterate f xfx에 반복 적용한 무한 리스트를 돌려줘요:

iterate f x  ==  [x, f x, f (f x), ...]
repeat :: a -> [a]

repeat x는 모든 요소의 값이 x인 무한 리스트예요.

replicate :: Int -> a -> [a]

replicate n x는 모든 요소의 값이 x인 길이 n의 리스트예요. 이것은 n이 어떤 정수 타입이든 될 수 있는 더 일반적인 Data.List.genericReplicate의 한 인스턴스예요.

cycle :: [a] -> [a]

cycle은 유한 리스트를 순환 리스트로 묶어요. 즉 원래 리스트의 무한 반복과 동등해요. 무한 리스트에 대해서는 항등 함수예요.

펼치기 (Unfolding)

unfoldr :: (b -> Maybe (a, b)) -> b -> [a]

unfoldr 함수는 foldr의 '쌍대(dual)'예요. foldr이 리스트를 요약값으로 축소하는 반면, unfoldr은 시드(seed) 값에서 리스트를 만듭니다. 함수는 요소를 받아 리스트 생산을 끝냈다면 Nothing을 돌려주거나, Just (a,b)를 돌려주는데 이 경우 a가 리스트에 앞에 추가되고 b가 재귀 호출의 다음 요소로 사용돼요. 예를 들어,

iterate f  ==  unfoldr (\x -> Just (x, f x))

어떤 경우에는 unfoldrfoldr 연산을 되돌릴 수 있어요:

unfoldr f' (foldr f z xs)  ==  xs

다음이 성립한다면요:

f' (f x y)  =  Just (x,y)
f' z        =  Nothing

unfoldr의 간단한 사용:

unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10
[10,9,8,7,6,5,4,3,2,1]

20.5 부분 리스트 (Sublists)

부분 리스트 추출 (Extracting sublists)

take :: Int -> [a] -> [a]

take n을 리스트 xs에 적용하면 xs의 길이 n 접두부(prefix)를 돌려주거나, n > length xs이면 xs 자체를 돌려줘요:

take 5 "Hello World!"  ==  "Hello"
take 3 [1,2,3,4,5]     ==  [1,2,3]
take 3 [1,2]           ==  [1,2]
take 3 []              ==  []
take (-1) [1,2]        ==  []
take 0 [1,2]           ==  []

이것은 n이 어떤 정수 타입이든 될 수 있는 더 일반적인 Data.List.genericTake의 한 인스턴스예요.

drop :: Int -> [a] -> [a]

drop n xs는 앞의 n개 요소 뒤의 xs 접미부(suffix)를 돌려주거나, n > length xs이면 []를 돌려줘요:

drop 6 "Hello World!"  ==  "World!"
drop 3 [1,2,3,4,5]     ==  [4,5]
drop 3 [1,2]           ==  []
drop 3 []              ==  []
drop (-1) [1,2]        ==  [1,2]
drop 0 [1,2]           ==  [1,2]

이것은 n이 어떤 정수 타입이든 될 수 있는 더 일반적인 Data.List.genericDrop의 한 인스턴스예요.

splitAt :: Int -> [a] -> ([a], [a])

splitAt n xs는 첫 요소가 xs의 길이 n 접두부이고 두 번째 요소가 리스트의 나머지인 튜플을 돌려줘요:

splitAt 6 "Hello World!"  ==  ("Hello ","World!")
splitAt 3 [1,2,3,4,5]     ==  ([1,2,3],[4,5])
splitAt 1 [1,2,3]         ==  ([1],[2,3])
splitAt 3 [1,2,3]         ==  ([1,2,3],[])
splitAt 4 [1,2,3]         ==  ([1,2,3],[])
splitAt 0 [1,2,3]         ==  ([],[1,2,3])
splitAt (-1) [1,2,3]      ==  ([],[1,2,3])

이것은 (take n xs, drop n xs)와 동등해요. splitAtn이 어떤 정수 타입이든 될 수 있는 더 일반적인 Data.List.genericSplitAt의 한 인스턴스예요.

takeWhile :: (a -> Bool) -> [a] -> [a]

takeWhile을 술어 p와 리스트 xs에 적용하면 p를 만족하는 요소들의 xs의 가장 긴 접두부(비어 있을 수도 있음)를 돌려줘요:

takeWhile (< 3) [1,2,3,4,1,2,3,4]  ==  [1,2]
takeWhile (< 9) [1,2,3]            ==  [1,2,3]
takeWhile (< 0) [1,2,3]            ==  []
dropWhile :: (a -> Bool) -> [a] -> [a]

dropWhile p xstakeWhile p xs 뒤에 남는 접미부를 돌려줘요:

dropWhile (< 3) [1,2,3,4,5,1,2,3]  ==  [3,4,5,1,2,3]
dropWhile (< 9) [1,2,3]            ==  []
dropWhile (< 0) [1,2,3]            ==  [1,2,3]
span :: (a -> Bool) -> [a] -> ([a], [a])

span을 술어 p와 리스트 xs에 적용하면 첫 요소가 p를 만족하는 요소들의 xs의 가장 긴 접두부(비어 있을 수도 있음)이고 두 번째 요소가 리스트의 나머지인 튜플을 돌려줘요:

span (< 3) [1,2,3,4,1,2,3,4]  ==  ([1,2],[3,4,1,2,3,4])
span (< 9) [1,2,3]            ==  ([1,2,3],[])
span (< 0) [1,2,3]            ==  ([],[1,2,3])

span p xs(takeWhile p xs, dropWhile p xs)와 동등해요.

break :: (a -> Bool) -> [a] -> ([a], [a])

break를 술어 p와 리스트 xs에 적용하면 첫 요소가 p를 만족하지 않는 요소들의 xs의 가장 긴 접두부(비어 있을 수도 있음)이고 두 번째 요소가 리스트의 나머지인 튜플을 돌려줘요:

break (> 3) [1,2,3,4,1,2,3,4]  ==  ([1,2,3],[4,1,2,3,4])
break (< 9) [1,2,3]            ==  ([],[1,2,3])
break (> 9) [1,2,3]            ==  ([1,2,3],[])

break pspan (not . p)와 동등해요.

stripPrefix :: Eq a => [a] -> [a] -> Maybe [a]

stripPrefix 함수는 주어진 접두부를 리스트에서 제거해요. 리스트가 주어진 접두부로 시작하지 않으면 Nothing을 돌려주고, 시작하면 접두부 뒤의 리스트를 Just로 돌려줘요.

stripPrefix "foo" "foo"       ==  Just ""
stripPrefix "foo" "foobar"    ==  Just "bar"
stripPrefix "foo" "barfoo"    ==  Nothing
stripPrefix "foo" "barfoobaz" ==  Nothing
group :: Eq a => [a] -> [[a]]

group 함수는 리스트를 받아 결과의 이어붙임(concatenation)이 인자와 같은 리스트의 리스트를 돌려줘요. 게다가 결과의 각 부분 리스트는 같은 요소만을 포함해요. 예를 들어,

group "Mississippi"  =  ["M","i","ss","i","ss","i","pp","i"]

이것은 프로그래머가 자신의 동등성 검사를 제공할 수 있는 groupBy의 특수한 경우예요.

inits :: [a] -> [[a]]

inits 함수는 인자의 모든 초기 구간(initial segment)을 가장 짧은 것부터 돌려줘요. 예를 들어,

inits "abc"  ==  ["","a","ab","abc"]
tails :: [a] -> [[a]]

tails 함수는 인자의 모든 끝 구간(final segment)을 가장 긴 것부터 돌려줘요. 예를 들어,

tails "abc"  ==  ["abc", "bc", "c",""]

20.6 술어 (Predicates)

isPrefixOf :: Eq a => [a] -> [a] -> Bool

isPrefixOf 함수는 두 리스트를 받아 첫 리스트가 두 번째 리스트의 접두부이면 True를 돌려줘요.

isSuffixOf :: Eq a => [a] -> [a] -> Bool

isSuffixOf 함수는 두 리스트를 받아 첫 리스트가 두 번째 리스트의 접미부이면 True를 돌려줘요. 두 리스트 모두 유한해야 해요.

isInfixOf :: Eq a => [a] -> [a] -> Bool

isInfixOf 함수는 두 리스트를 받아 첫 리스트가 완전히 온전한 상태로 두 번째 리스트 어딘가에 포함되어 있으면 True를 돌려줘요. 예:

isInfixOf "Haskell" "I really like Haskell."  ==  True
isInfixOf "Ial"     "I really like Haskell."  ==  False

20.7 리스트 검색 (Searching lists)

동등성으로 검색 (Searching by equality)

elem :: Eq a => a -> [a] -> Bool

elem은 리스트 소속 술어로, 보통 중위(infix) 형태로 써요. 예를 들어 x elem xs. 결과가 False가 되려면 리스트가 유한해야 하고, True는 유한하거나 무한한 리스트의 유한 인덱스에서 x와 같은 요소를 찾을 때 나와요.

notElem :: Eq a => a -> [a] -> Bool

notElemelem의 부정이에요.

lookup :: Eq a => a -> [(a, b)] -> Maybe b

lookup key assocs는 연관 리스트에서 키를 찾아요.

술어로 검색 (Searching with a predicate)

find :: (a -> Bool) -> [a] -> Maybe a

find 함수는 술어와 리스트를 받아 리스트에서 술어와 맞는 첫 번째 요소를 돌려주거나, 그런 요소가 없으면 Nothing을 돌려줘요.

filter :: (a -> Bool) -> [a] -> [a]

filter를 술어와 리스트에 적용하면 술어를 만족하는 요소들의 리스트를 돌려줘요. 즉,

filter p xs  =  [ x | x <- xs, p x]
partition :: (a -> Bool) -> [a] -> ([a], [a])

partition 함수는 술어와 리스트를 받아 술어를 만족하는 요소들의 리스트와 만족하지 않는 요소들의 리스트의 쌍을 돌려줘요. 즉,

partition p xs  ==  (filter p xs, filter (not . p) xs)

20.8 리스트 인덱싱 (Indexing lists)

(!!) :: [a] -> Int -> a

0부터 시작하는 리스트 인덱스(첨자) 연산자예요. 이것은 어떤 정수 타입의 인덱스를 받는 더 일반적인 Data.List.genericIndex의 한 인스턴스예요.

elemIndex :: Eq a => a -> [a] -> Maybe Int

elemIndex 함수는 주어진 리스트에서 ==로 쿼리 요소와 같은 첫 번째 요소의 인덱스를 돌려주거나, 그런 요소가 없으면 Nothing을 돌려줘요.

elemIndices :: Eq a => a -> [a] -> [Int]

elemIndices 함수는 쿼리 요소와 같은 모든 요소의 인덱스를 오름차순으로 돌려줌으로써 elemIndex를 확장해요.

findIndex :: (a -> Bool) -> [a] -> Maybe Int

findIndex 함수는 술어와 리스트를 받아 리스트에서 술어를 만족하는 첫 번째 요소의 인덱스를 돌려주거나, 그런 요소가 없으면 Nothing을 돌려줘요.

findIndices :: (a -> Bool) -> [a] -> [Int]

findIndices 함수는 술어를 만족하는 모든 요소의 인덱스를 오름차순으로 돌려줌으로써 findIndex를 확장해요.

20.9 리스트 지퍼·언지퍼 (Zipping and unzipping lists)

zip :: [a] -> [b] -> [(a, b)]

zip은 두 리스트를 받아 대응하는 쌍들의 리스트를 돌려줘요. 입력 리스트 중 하나가 짧으면 더 긴 리스트의 초과 요소는 버려져요.

zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]

zip3은 세 리스트를 받아 zip과 유사한 삼중(triple) 리스트를 돌려줘요.

zip4 :: [a] -> [b] -> [c] -> [d] -> [(a, b, c, d)]

zip4 함수는 네 리스트를 받아 zip과 유사한 사중(quadruple) 리스트를 돌려줘요.

zip5 :: [a] -> [b] -> [c] -> [d] -> [e] -> [(a, b, c, d, e)]

zip5 함수는 다섯 리스트를 받아 zip과 유사한 오중(five-tuple) 리스트를 돌려줘요.

zip6 :: [a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [(a, b, c, d, e, f)]

zip6 함수는 여섯 리스트를 받아 zip과 유사한 육중(six-tuple) 리스트를 돌려줘요.

zip7 :: [a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [g] -> [(a, b, c, d, e, f, g)]

zip7 함수는 일곱 리스트를 받아 zip과 유사한 칠중(seven-tuple) 리스트를 돌려줘요.

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

zipWith는 튜플링 함수 대신 첫 번째 인자로 주어진 함수로 지퍼링함으로써 zip을 일반화해요. 예를 들어 zipWith (+)는 두 리스트에 적용해 대응하는 합들의 리스트를 만드는 데 사용돼요.

zipWith3 :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]

zipWith3 함수는 세 요소를 결합하는 함수와 세 리스트를 받아 zipWith와 유사한 그들의 점별(point-wise) 결합 리스트를 돌려줘요.

zipWith4 :: (a -> b -> c -> d -> e) -> [a] -> [b] -> [c] -> [d] -> [e]

zipWith4 함수는 네 요소를 결합하는 함수와 네 리스트를 받아 zipWith와 유사한 그들의 점별 결합 리스트를 돌려줘요.

zipWith5 :: (a -> b -> c -> d -> e -> f) -> [a] -> [b] -> [c] -> [d] -> [e] -> [f]

zipWith5 함수는 다섯 요소를 결합하는 함수와 다섯 리스트를 받아 zipWith와 유사한 그들의 점별 결합 리스트를 돌려줘요.

zipWith6 :: (a -> b -> c -> d -> e -> f -> g) -> [a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [g]

zipWith6 함수는 여섯 요소를 결합하는 함수와 여섯 리스트를 받아 zipWith와 유사한 그들의 점별 결합 리스트를 돌려줘요.

zipWith7 :: (a -> b -> c -> d -> e -> f -> g -> h) -> [a] -> [b] -> [c] -> [d] -> [e] -> [f] -> [g] -> [h]

zipWith7 함수는 일곱 요소를 결합하는 함수와 일곱 리스트를 받아 zipWith와 유사한 그들의 점별 결합 리스트를 돌려줘요.

unzip :: [(a, b)] -> ([a], [b])

unzip은 쌍들의 리스트를 첫 번째 성분들의 리스트와 두 번째 성분들의 리스트로 변환해요.

unzip3 :: [(a, b, c)] -> ([a], [b], [c])

unzip3 함수는 삼중들의 리스트를 받아 unzip과 유사한 세 리스트를 돌려줘요.

unzip4 :: [(a, b, c, d)] -> ([a], [b], [c], [d])

unzip4 함수는 사중들의 리스트를 받아 unzip과 유사한 네 리스트를 돌려줘요.

unzip5 :: [(a, b, c, d, e)] -> ([a], [b], [c], [d], [e])

unzip5 함수는 오중들의 리스트를 받아 unzip과 유사한 다섯 리스트를 돌려줘요.

unzip6 :: [(a, b, c, d, e, f)] -> ([a], [b], [c], [d], [e], [f])

unzip6 함수는 육중들의 리스트를 받아 unzip과 유사한 여섯 리스트를 돌려줘요.

unzip7 :: [(a, b, c, d, e, f, g)] -> ([a], [b], [c], [d], [e], [f], [g])

unzip7 함수는 칠중들의 리스트를 받아 unzip과 유사한 일곱 리스트를 돌려줘요.

20.10 특수 리스트 (Special lists)

문자열 함수 (Functions on strings)

lines :: String -> [String]

lines은 문자열을 줄바꿈 문자에서 문자열들의 리스트로 나눠요. 결과 문자열들은 줄바꿈을 포함하지 않아요.

words :: String -> [String]

words는 문자열을 공백으로 구분된 단어들의 리스트로 나눠요.

unlines :: [String] -> String

unlineslines의 역연산이에요. 각 줄에 종결 줄바꿈을 추가한 뒤 줄들을 이어붙여요.

unwords :: [String] -> String

unwordswords의 역연산이에요. 단어들을 분리 공백으로 이어붙여요.

“집합” 연산 (“Set” operations)

nub :: Eq a => [a] -> [a]

O(n^2). nub 함수는 리스트에서 중복 요소를 제거해요. 특히 각 요소의 첫 번째 발생만 유지해요. (이름 nub은 '본질(essence)'을 뜻해요.) 이것은 프로그래머가 자신의 동등성 검사를 제공할 수 있는 nubBy의 특수한 경우예요.

delete :: Eq a => a -> [a] -> [a]

delete x는 리스트 인자에서 x의 첫 번째 발생을 제거해요. 예를 들어,

delete 'a' "banana"  ==  "bnana"

이것은 프로그래머가 자신의 동등성 검사를 제공할 수 있는 deleteBy의 특수한 경우예요.

(\\) :: Eq a => [a] -> [a] -> [a]

\\ 함수는 리스트 차(list difference)예요(결합 법칙이 아님). 결과 xs \\ ys에서는 ys의 각 요소의 첫 번째 발생(있을 경우)이 차례로 xs에서 제거돼요. 따라서 (xs ++ ys) \\ xs == ys예요. 이것은 프로그래머가 자신의 동등성 검사를 제공할 수 있는 deleteFirstsBy의 특수한 경우예요.

union :: Eq a => [a] -> [a] -> [a]

union 함수는 두 리스트의 리스트 합집합을 돌려줘요. 예를 들어,

"dog" `union` "cow"  ==  "dogcw"

중복과 첫 리스트의 요소는 두 번째 리스트에서 제거되지만, 첫 리스트에 중복이 있으면 결과에도 중복이 생겨요. 이것은 프로그래머가 자신의 동등성 검사를 제공할 수 있는 unionBy의 특수한 경우예요.

intersect :: Eq a => [a] -> [a] -> [a]

intersect 함수는 두 리스트의 리스트 교집합을 취해요. 예를 들어,

[1,2,3,4] `intersect` [2,4,6,8]  ==  [2,4]

첫 리스트에 중복이 있으면 결과에도 중복이 생겨요.

[1,2,2,3,4] `intersect` [6,4,4,2]  ==  [2,2,4]

이것은 프로그래머가 자신의 동등성 검사를 제공할 수 있는 intersectBy의 특수한 경우예요.

정렬된 리스트 (Ordered lists)

sort :: Ord a => [a] -> [a]

sort 함수는 안정적(stable) 정렬 알고리즘을 구현해요. 이것은 프로그래머가 자신의 비교 함수를 제공할 수 있는 sortBy의 특수한 경우예요.

insert :: Ord a => a -> [a] -> [a]

insert 함수는 요소와 리스트를 받아, 다음 요소보다 여전히 작거나 같은 마지막 위치에 요소를 삽입해요. 특히 호출 전에 리스트가 정렬되어 있으면 결과도 정렬돼요. 이것은 프로그래머가 자신의 비교 함수를 제공할 수 있는 insertBy의 특수한 경우예요.

20.11 일반화된 함수 (Generalized functions)

” By ” 연산 (The "By" operations)

사용자 제공 동등성 (User-supplied equality; replacing an Eq context)
nubBy :: (a -> a -> Bool) -> [a] -> [a]

nubBy 함수는 오버로드된 == 함수 대신 사용자 제공 동등성 술어를 사용한다는 점 외에는 nub과 똑같이 동작해요.

deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]

deleteBy 함수는 사용자 제공 동등성 술어를 취한다는 점 외에는 delete처럼 동작해요.

deleteFirstsBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]

deleteFirstsBy 함수는 술어와 두 리스트를 받아, 두 번째 리스트의 각 요소의 첫 번째 발생을 제거한 첫 리스트를 돌려줘요.

unionBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]

unionBy 함수는 union의 비오버로드 버전이에요.

intersectBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]

intersectBy 함수는 intersect의 비오버로드 버전이에요.

groupBy :: (a -> a -> Bool) -> [a] -> [[a]]

groupBy 함수는 group의 비오버로드 버전이에요.

사용자 제공 비교 (User-supplied comparison; replacing an Ord context)
sortBy :: (a -> a -> Ordering) -> [a] -> [a]

sortBy 함수는 sort의 비오버로드 버전이에요.

insertBy :: (a -> a -> Ordering) -> a -> [a] -> [a]

insert의 비오버로드 버전이에요.

maximumBy :: (a -> a -> Ordering) -> [a] -> a

maximumBy 함수는 비교 함수와 리스트를 받아 비교 함수로 보아 리스트에서 가장 큰 요소를 돌려줘요. 리스트는 유한하고 비어 있지 않아야 해요.

minimumBy :: (a -> a -> Ordering) -> [a] -> a

minimumBy 함수는 비교 함수와 리스트를 받아 비교 함수로 보아 리스트에서 가장 작은 요소를 돌려줘요. 리스트는 유한하고 비어 있지 않아야 해요.

” generic ” 연산 (The "generic" operations)

genericLength :: Num i => [b] -> i

genericLength 함수는 length의 오버로드 버전이에요. 특히 Int를 돌려주는 대신 Num의 인스턴스인 어떤 타입이든 돌려줘요. 다만 length보다는 덜 효율적이에요.

genericTake :: Integral i => i -> [a] -> [a]

genericTake 함수는 취할 요소 수로 어떤 Integral 값이든 받는 take의 오버로드 버전이에요.

genericDrop :: Integral i => i -> [a] -> [a]

genericDrop 함수는 버릴 요소 수로 어떤 Integral 값이든 받는 drop의 오버로드 버전이에요.

genericSplitAt :: Integral i => i -> [b] -> ([b], [b])

genericSplitAt 함수는 분리 위치로 어떤 Integral 값이든 받는 splitAt의 오버로드 버전이에요.

genericIndex :: Integral a => [b] -> a -> b

genericIndex 함수는 인덱스로 어떤 Integral 값이든 받는 !!의 오버로드 버전이에요.

genericReplicate :: Integral i => i -> a -> [a]

genericReplicate 함수는 반복 횟수로 어떤 Integral 값이든 받는 replicate의 오버로드 버전이에요.

더 알아보기 (Learn more)

  • 대부분의 함수는 술어나 비교 함수를 받는 By 계열(nubBy, sortBy, groupBy 등)과 generic 계열(genericLength, genericTake 등)로 일반화돼요.
  • 문자열 조작(lines, words 등)과 세트 연산(nub, union, intersect 등)은 실무에서 자주 쓰이는 함수들이에요.