跳轉到內容

Haskell/Solutions/列表 II

來自華夏公益教科書,開放的書籍,面向開放的世界

← 返回列表 II

請注意,對於我們目前的用途而言,使用Int還是Integer無關緊要,所以如果你使用了其中一個,而下面的解決方案使用了另一個,請不要擔心。

重建列表

[編輯 | 編輯原始碼]

1.

takeInt          :: Int -> [a] -> [a]
takeInt 0 _      = []
takeInt _ []     = []
takeInt n (x:xs) = x : takeInt (n-1) xs

2.

dropInt          :: Int -> [a] -> [a]
dropInt 0 list   = list
dropInt _ []     = []
dropInt n (x:xs) = dropInt (n-1) xs

3.

sumInt        :: [Int] -> Int
sumInt []     = 0
sumInt (x:xs) = x + sumInt xs

4.

-- "Direct" solution with pattern matching.
scanSum ::  [Int] -> [Int]
scanSum [] = []
scanSum [x] = [x]
scanSum (x:y:xs) = x : scanSum ((x + y) : xs)

-- Alternatively, using a helper function with an accumulator argument:
scanSum :: [Int] -> [Int]
scanSum = scanSum' 0
    where
    -- The following type signature is entirely optional.
    -- We have added it just for extra clarity.
    scanSum' :: Int -> [Int] -> [Int]
    scanSum' tot [] = []
    scanSum' tot (x:xs) = tot' : scanSum' tot' xs
        where
        tot' = x + tot

-- Alternatively, using takeInt, dropInt and sumInt:
scanSum :: [Int] -> [Int]
scanSum [] = []
scanSum [x] = [x]
scanSum (x:xs) = x : scanSum ((x + sumInt (takeInt 1 xs)) : dropInt 1 xs)

5.

diffs :: [Int] -> [Int]
diffs [] = []
diffs (x:xs) = diffs' (x:xs) xs
    where
    diffs' :: [Int] -> [Int] -> [Int]
    diffs' _ [] = []
    diffs' [] _ = []
    diffs' (x:xs) (y:ys) = (y-x) : diffs' xs ys

-- Alternatively, without the auxiliary function:
diffs          :: [Int] -> [Int]
diffs []       = []
diffs [x]      = []
diffs (x:y:xs) = (y-x) : diffs (y:xs)

map 函式

[編輯 | 編輯原始碼]

1. 每個函式的幾種變體將在下面單獨的程式碼塊中顯示

negateList, negateList2 :: [Int] -> [Int]
negateList = map negate
negateList2 xs = map negate xs

divisorsList, divisorsList2 :: [Int] -> [[Int]]
divisorsList = map divisors
divisorsList2 xs = map divisors xs

-- Note that there are even more possible ways of writing this one.
-- Remember that the dot operator composes functions: (g . f) x = g (f x) 
negateDivisorsList, negateDivisorsList2, negateDivisorsList3, negateDivisorsList4 :: [Int] -> [[Int]]
negateDivisorsList = map (negateList . divisors)
negateDivisorsList2 = map negateList . divisorsList
negateDivisorsList3 list = map (negateList . divisors) list
negateDivisorsList4 list = map (map negate) (map divisors list)

2. 一個可能的解決方案

import Data.List

myRLEencoder :: String -> [(Int, Char)]
myRLEencoder s = map pairRLE (group s)
    where
    pairRLE xs = (length xs, head xs) 

myRLEdecoder :: [(Int, Char)] -> String
myRLEdecoder l = concat (map expandRLE l)
    where
    expandRLE (n, x) = replicate n x

注意:RLE 示例的靈感來自 Don Stewart 在同一主題上發表的一篇 部落格文章。如果你好奇,可以檢視 Don 的文章,其中有一個巧妙的解決方案,你可能無法立即理解,因為它使用了一些我們尚未見過的內容。

技巧和竅門

[編輯 | 編輯原始碼]

1. scanSum (takeInt 10 [1..])takeInt 10 (scanSum [1..]) 的值相同。這是可能的,因為 Haskell 是一種惰性語言,因此在這兩種情況下,結果只有在需要時才會計算。

2.

-- This is just like the Prelude function last.
lastOf :: [a] -> a
lastOf [] = error "Empty list"
lastOf [x] = x
lastOf (_:xs) = lastOf xs
 
-- This is just like the Prelude init.
dropLast :: [a] -> [a]
dropLast [] = error "Empty list"
dropLast [x] = []
dropLast (x:xs) = x : (dropLast xs)
華夏公益教科書