一個串列中連續的任意一截被稱作一個「區段」(segment)。
例如,[1,2,3] 的區段包括[],[1],[2],[3],[1,2],[2,3], 以及
[1,2,3]本身(注意:空串列也是一個區段)。
也許因為歷史因素,許多有趣的演算法問題有這樣的形式:
給定一個串列 xs :: List A,一個述語 p :: List A -> Bool, 和一個函數 f :: List A -> B,我們想在 xs 的所有區段中,找出滿足述語 p 並使得 f 值最大的那個。
我們把這類問題統稱為「區段問題」。
本節討論一些簡單的區段問題。我們先回顧一下區段的形式定義。
第2.6.3 節曾提及,下述函數 segments 算出一個串列的所有區段:
segments :: List a -> List (List a)
segments = concat . map inits . tails
其中 tails :: List a -> List (List a) 計算一個串列所有的後段(suffixes),例如 tails [1,2,3] =
[[1,2,3],[2,3],[3],[]];
函數 inits :: List a -> List (List a) 則計算一個串列的所有前段(prefixes),例如 inits [1,2,3] = [[],[1],[1,2],[1,2,3]].
對每一個後段,計算所有的前段,便得到所有的區段了。
我們也可以反過來,定義 segments = concat . map tails . inits. 本節中的所有推導與證明可調整成相對應的版本。
事實上,如此的定義之下 segments [1,2,3] 會將空串列傳回很多次。
不過以本章的目的而言,我們對這些重複的 [] 並不在意。
為方便讀者,我們將 inits 與 tails 的歸納定義重複如下。
inits :: List a -> List (List a)
inits [] = [[]]
inits (x:xs) = [] : map (x:) (inits xs)
tails :: List a -> List (List a)
tails [] = [[]]
tails (x:xs) = (x:xs) : tails xs