跳转到内容

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)
华夏公益教科书