我的代碼正在運行,但不適用于無休止的串列。我怎樣才能使它作業?
sumsOf :: Num a => [[a]] -> [a]
sumsOf a = map sum [ x | x <- a , length x < 3]
例子 :
sumsOf [[],[1,2,4],[],[6]] == [0,0,6]
sumsOf [[1],[8],[6],[],[9,9]] == [1,8,6,0,18]
sumsOf [[1,2,9,10],[7,8,9],[6,9,4,2,0],[9,9,9]] == []
sumsOf [[1..],[7..],[6..],[9..],[10..],[100..]] == []
sumsOf [[1,2], [1..], [], [4]] == [3,0,4]
uj5u.com熱心網友回復:
length是串列函式之一,根據經驗,您應該永遠不要使用,除非您確切知道它為什么可以。(另一個是headand !!。)這不僅是因為它不適用于無限串列,還因為它通常對整個串列進行了完全不必要的O ( n ) 遍歷。即使您以后需要遍歷它,執行兩次也會產生很大的性能差異。
在這種情況下,想想你真正需要什么:sum避免進入一個長串列或無限串列,而是在兩個元素之后放棄。這實際上可以以一種愚蠢的疲憊方式實作:
sumIfLenLt3 :: Num a => [a] -> Maybe a
sumIfLenLt3 [] = Just 0
sumIfLenLt3 [x] = Just x
sumIfLenLt3 [x,y] = Just $ x y
sumIfLenLt3 _ = Nothing
為了使其適用于任何最大長度,您可以使用遞回:
sumIfLenLe :: Num a => Int -> [a] -> Maybe a
sumIfLenLe _ [] = Just 0
sumIfLenLe 0 _ = Nothing
sumIfLenLe n (h:t) = h sumIfLenLe (n-1) t
...但這不是一個很好的實作,有兩個原因:它會因否定論點而崩潰,而且它不是尾遞回。一個更好的,雖然有點麻煩,版本會是
sumIfLenLe :: Num a => Int -> [a] -> Maybe a
sumIfLenLe n l
| n<0 = Nothing
| otherwise = go n l 0
where go n [] acc = Just acc
go 0 _ _ = Nothing
go n (h:t) acc = go (n-1) t (h acc)
更優雅一點的是使用標準函式來獲取元素的最大可用數量,看看是否還有任何東西:
sumIfLenLe :: Num a => Int -> [a] -> Maybe a
sumIfLenLe n l
| null remains = Just $ sum relevant
| otherwise = Nothing
where (relevant, remains) = splitAt n l
...或者,一些等效的形式,
sumIfLenLe n l = case splitAt n l of
(relevant, []) -> Just $ sum relevant
_ -> Nothing
或者
sumIfLenLe n l
| (relevant, []) <- splitAt n l
= Just $ sum relevant
| otherwise = Nothing
然后,您可以將其映射到整個給定串列并收集所有成功的結果。
import Data.Maybe (catMaybes)
sumsOf :: Num a => [[a]] -> [a]
sumsOf = catMaybes . map (sumIfLe 2)
uj5u.com熱心網友回復:
輕松懶惰的解決方案:
您只關心長度是否小于 3,因此如果您將輸入串列截斷為 3 個元素,結果不會改變:
$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/ :? for help
λ>
λ> sumsOf a = map sum [ x | x <- a , length (take 3 x) < 3]
λ>
λ> sumsOf [[],[1,2,4],[],[6]]
[0,0,6]
λ> sumsOf [[1],[8],[6],[],[9,9]]
[1,8,6,0,18]
λ> sumsOf [[1,2,9,10],[7,8,9],[6,9,4,2,0],[9,9,9]]
[]
λ> sumsOf [[1..],[7..],[6..],[9..],[10..],[100..]]
[]
λ> sumsOf [[1,2], [1..], [], [4]]
[3,0,4]
λ>
所以這很容易解決無限串列的問題。
以稍微更慣用的方式:
sumsOf :: Num a => [[a]] -> [a]
sumsOf xss = map sum [ xs | xs <- xss , length (take 3 xs) < 3]
唯一的缺點是庫函式take必須復制串列節點。
n.1.8e9-where's-my-sharem 在評論中提到的一個想法:通過撰寫一些boundedLength最多回傳的函式,可以使效率更高一些k,例如:
boundedLength :: Int -> [a] -> Int
boundedLength k xs = go 0 xs
where
go depth [] = depth
go depth (x:xs) = if (depth < k) then go (depth 1) xs
else k
在這種情況下,我們的sumsOf函式最終為:
sumsOf :: Num a => [[a]] -> [a]
sumsOf xss = map sum [ xs | xs <- xss , boundedLength 3 xs < 3]
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/495982.html
標籤:哈斯克尔
