實作
isLengthEven :: [a] -> Bool決定串列是否包含偶數個元素的函式。在本練習中,length禁止使用回傳串列元素數量的函式或任何其他函式。提示:我們需要檢查的是我們是否可以兩兩遍歷整個串列,或者函式是否在最后遺漏了一個專案。
例如:
isLengthEven "Apple" == True,isLengthEven "Even" == True,isLengthEven [] == False
到目前為止,我嘗試了模式匹配和遞回,在我看來,這是進行此練習的最佳方式。我的代碼如下:
isLengthEven :: [a] -> Bool
isLengthEven [] = False
isLengthEven (x:[]) = False
isLengthEven (x:(y:[])) = True
isLengthEven (x:(y:(z:[]))) = False
isLengthEven (x:(y:(z:(q:[])))) = True
isLengthEven (x:xs) = isLengthEven (xs)
這將回傳正確的值,直到我將第五個元素插入串列中。它回傳True大于或等于 5 的任意數量的元素。我想遞回部分有問題。
uj5u.com熱心網友回復:
您在這里只需要兩個基本情況:
- 一個空串列,它具有 as 長度
0,因此應該回傳True;和 - 包含一個元素并因此具有奇數長度的單例串列。
遞回情況每次在串列中向前移動兩步,因此:
isLengthEven :: [a] -> Bool
isLengthEven [] = True
isLengthEven [x] = False
isLengthEven (_:_:xs) = isLengthEven xs
常常一個定義了兩個函式:isLengthEven和isLengthOdd并且因此這些功能每次相互呼叫遞回地:
isLengthEven :: [a] -> Bool
isLengthEven [] = True
isLengthEven (_:xs) = isLengthOdd xs
isLengthOdd :: [a] -> Bool
isLengthOdd [] = False
isLengthOdd (_:xs) = isLengthEven xs
uj5u.com熱心網友回復:
單步解決方案
請注意,Willem的優秀答案已經是優化的答案。
如果您更喜歡未經優化的直接版本并選擇忽略提示,則可以僅使用初始代碼的第一個和最后一個子句。像這樣:
-- warning: the following is incorrect, needs changes:
isLengthEven :: [a] -> Bool
isLengthEven [] = False
isLengthEven (x:xs) = isLengthEven (xs)
這兩個子句都不正確,但很容易修復它們:
isLengthEven :: [a] -> Bool
isLengthEven [] = True
isLengthEven (x:xs) = not (isLengthEven xs)
綜合起來,這兩個條款涵蓋了所有可能的情況。
附錄:
照原樣,此函式為長輸入使用了大量堆疊空間。這可以通過常見的累加器作為引數的技巧來解決。這里:
isLengthEven :: [a] -> Bool
isLengthEven xs = go True xs where
go b [] = b
go b (x:xs) = go (not b) xs
其中go輔助步進函式是尾遞回的。
在我的機器上,這個單步解決方案(包括最后一個更改)的性能非常接近問題文本中提倡的“兩兩”解決方案。
這兩種方法的性能都是直接但被禁止的(even (length xs))解決方案的三分之二左右。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/327783.html
上一篇:如何替換Python中鍵的值?
下一篇:我可以在地圖功能中設定狀態嗎?
