如何解決這些錯誤
注:雖然我會告訴你如何認識和解決這些錯誤,我也呈現出更優雅版(至少從我的角度來看)以下。
當你結束了一個無限的類型,這是一個好主意太添加類型簽名:
cpfx' :: [[Char]] -> Int -> [Char]
ifMatch :: [[Char]] -> Int -> Bool
突然,我們獲得了更多的錯誤,兩人在
| ifMatch (x:t) n = x!!n + cpfx' x (n+1)
Couldn't match expected type `[Char]' with actual type `Char'
Expected type: [[Char]]
Actual type: [Char]
In the first argument of `(!!)', namely `x'
In the first argument of `(+)', namely `x !! n'
No instance for (Num [Char])
arising from a use of `+'
and in ifMatch
:
| x!!n == x!!n = ifMatch xs n
Couldn't match expected type `[Char]' with actual type `Char'
Expected type: [[Char]]
Actual type: [Char]
In the first argument of `ifMatch', namely `xs'
In the expression: ifMatch xs n
現在,cpfx'
錯誤很簡單:x
是[Char]
,x !! n
是Char
,並希望利弊它放到一個列表,所以使用:
代替+
。此外,您要申請cpfx'
至t
,而不是x
。這也解決了你的第二個錯誤。在ifMatch
,x!!n == x!!n
是多餘的,並且xs
具有類型[Char]
,因此對於ifMatch
沒有正確的類型。這也是一個錯字:
| x!!n == xs!!n = ifMatch t n
但是,現在我們修復了這些編譯錯誤,您的程序是否真的有意義?尤其是,你能指望什麼這行做的事:
ifMatch (x:xs) n = x!!n : cpfx' xs (n+1)
(x:xs)
是你的話清單。但是,您在每次迭代中都會刪除一個詞,這顯然不是您的意思。你想
ifMatch (x:xs) n = x!!n : cpfx' (x:xs) (n+1)
整體而言,我們得到如下代碼:
cpfx :: [[Char]] -> [Char]
cpfx [] = []
cpfx [x] = x
cpfx (x:xs) = cpfx' (x:xs) 0
cpfx' :: [[Char]] -> Int -> [Char]
cpfx' [x] _ = []
cpfx' (x:xs) n
| ifMatch (x:xs) n = x!!n : cpfx' (x:xs) (n+1)
| otherwise = []
ifMatch :: [[Char]] -> Int -> Bool
ifMatch [x] _ = True
ifMatch [x,y] n = x!!n == y!!n
ifMatch (x:y:xs) n
| x!!n == y!!n = ifMatch xs n
| otherwise = False
使用更簡單的方法摺疊
讓我們讓我們的功能有點簡單,但也比較一般寫爲commonPrefix
實現的任何類型==
:
commonPrefix :: (Eq e) => [e] -> [e] -> [e]
commonPrefix _ [] = []
commonPrefix [] _ = []
commonPrefix (x:xs) (y:ys)
| x == y = x : commonPrefix xs ys
| otherwise = []
如果y你不習慣那種符號,想象一下e
是Char
。現在,一些詞的共同的前綴可以寫成:
"hello" `commonPrefix` "hell" `commonPrefix` "hero"
現在的問題是,如果你想爲一系列的事情做的事情,你平時用fold:
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl, applied to a binary operator, a starting value (typically the left-identity of the operator), and a list, reduces the list using the binary operator, from left to right:
foldl f z [x1, x2, ..., xn] == (...((z `f` x1) `f` x2) `f`...) `f` xn
最後一個例子看起來和我們的\
commonPrefix` line before! However, we do not have a starting value, so we would use the first element of our list instead. Luckily, there's already [
foldl1`] 2完全一樣。因此,我們以前複雜的功能可以歸結爲:
commonPrefixAll :: (Eq a) => [[a]] -> [a]
commonPrefixAll = foldl1 commonPrefix
你應該從這個記住的是:每當你想要走過去列表中的多個元素,以提供一個值,想一想它是否是真的在每次迭代中都必須查看所有元素。通常,一次只關注兩個元素就足夠了,然後使用正確的摺疊。有關更多示例和信息,請參閱部分Computing one answer over a collection in Real World Haskell。
題外話:'環丙沙星[] = [] - 什麼都沒有,duh'不太所以「呃」。空的'[[a]]'的公共前綴是未定義的,即公共前綴可以是*任何*,因爲沒有任何東西可以作爲前綴進行測試。 – Onyxite