遞歸

2016-08-22 96 views
0

我想每兩個元素挑錯誤類型形成一個列表,使一個新的列表,然後我得到這樣的錯誤:遞歸

test.hs:4:20: error: 
? Couldn't match expected type ‘[a]’ with actual type ‘a’ 
    ‘a’ is a rigid type variable bound by 
    the type signature for: 
     test :: forall a. [a] -> [[a]] 
    at test.hs:1:7 
? In the expression: x1 
    In the expression: [x1] 
    In a case alternative: [x1] -> [x1] 
? Relevant bindings include 
    x1 :: a (bound at test.hs:4:6) 
    list :: [a] (bound at test.hs:2:6) 
    test :: [a] -> [[a]] (bound at test.hs:2:1) 

這裏是我的代碼:

test::[a]->[[a]] 
test list = case list of 
    []   ->[] 
    [x1]  ->[x1] 
    [x1,x2]  ->[x1,x2] 
    x1:x2:xs ->[[x1,x2],(test xs)] 

任何人都可以幫助我嗎?

+2

如果'[x1]'的類型是'[a]',那麼'[x1]'的類型是什麼? – leftaroundabout

回答

2

它通常在Haskell最好只寫一個函數的不同條款 - 這樣做同樣的事情case,但往往是更好的可讀性。另外,請不要給你的函數名稱如test

更好的是這樣的:

chunksÀ2 :: [a] -> [[a]] 
chunksÀ2 [] = [] 
chunksÀ2 [x1] = [x1] 
chunksÀ2 [x1,x2] = [x1,x2] 
chunksÀ2 (x1:x2:xs) = [[x1,x2], chunksÀ2 xs] 

現在,這些條款必須獨立進行類型檢查。我將從第二個開始:

chunksÀ2 [x1] = [x1] 

嗯。簽名表示結果應該是一個嵌套列表,並且輸入一個簡單的列表。因此可以肯定,你居然是說:

chunksÀ2 [x1] = [[x1]] 

這是一個列表,它的唯一元素是一個元素的列表。

下一個子句類似:

chunksÀ2 [x1,x2] = [[x1,x2]] 

注意

chunksÀ2 [x1,x2] = [[x1],[x2]] 

也將是可能的。 (練習:爲什麼是你不想要的東西)

它有趣的是遞歸的子句。您已正確彈出輸入列表中前兩個元素,其模式匹配爲x1:x2:xs。現在你需要重新組裝它們。​​在結果列表的第一個元素是正確的,但呢? chunksÀ2 xs[[a]],所以如果你把它放在另一個[]你會有類型[[[a]]]。這顯然是太多的包裝!

取而代之,您只需要預先​​到chunksÀ2 xs。那麼,使用cons運算符,你也用於模式匹配:

chunksÀ2 (x1:x2:xs) = [x1,x2] : chunksÀ2 xs 

最後是空的子句。這實際上是你寫作的方式,但你知道爲什麼嗎?需要注意的是[]可以有任何列表的你喜歡的類型:

Prelude> [] :: [Int] 
[] 
Prelude> [] :: [String] 
[] 
Prelude> [] :: [[(Double,[Maybe Bool])]] 
[] 

chunksÀ2 [] = [] 

你確實有

chunksÀ2 ([] :: [a]) = [] :: [[a]] 

你可能也寫

chunksÀ2 [] = [[]] 

但那個w不應該做正確的事情。

+0

這真的有道理。非常感謝! – kkkjjj

1

[],[x1],[x1, x2][[x1, x2], (test xs)]都必須具有相同類型纔是可能的相同功能的值。我想你在第三希望在第二種情況下[[x1]][[x1, x2]],因爲在那些兩起案件是完全最多兩個長度的一個大塊。需要注意的是,你甚至都不需要,因爲它是由第四涵蓋的xs = []第三種情況。你也可以跳過導入Data.List.Split並利用其chunksOf 2實現此功能。