HTNW объяснил, как делать то, что вы просили, но я подумал, что должен упомянуть, что для конкретного приложения, которое вы упомянули, в некоторых случаях есть способ, который более эффективен (при условии, что слова представлены String
с).Предположим, вы хотите
longest :: [[a]] -> [a]
Если вы попросите maximumOn length [replicate (10^9) (), []]
, то в итоге вы без необходимости рассчитаете длину очень длинного списка.Есть несколько способов обойти эту проблему, но вот как я бы это сделал:
data MS a = MS
{ _longest :: [a]
, _longest_suffix :: [a]
, _longest_bound :: !Int }
Мы позаботимся о том, чтобы longest
была первой из самых длинных строк, которые были до сих пор, и что longest_bound + length longest_suffix = length longest
.
step :: MS a -> [a] -> MS a
step (MS longest longest_suffix longest_bound) xs =
go longest_bound longest_suffix xs'
where
-- the new list is not longer
go n suffo [] = MS longest suffo n
-- the new list is longer
go n [] suffn = MS xs suffn n
-- don't know yet
go !n (_ : suffo) (_ : suffn) =
go (n + 1) suffo suffn
xs' = drop longest_bound xs
longest :: [[a]] -> [a]
longest = _longest . foldl' step (MS [] [] 0)
Теперь, если список от второго до самого длинного содержит q
элементов, мы пройдем не более q
в каждом списке.Это наилучшая возможная сложность.Конечно, это только значительно лучше, чем решение maximumOn
, когда самый длинный список намного длиннее, чем второй, самый длинный.