2016-03-04 57 views
0

我做了一個像這樣的錯誤的線程,其中我解釋了我的程序。這裏的the link錯誤:函數Haskell中的非窮舉模式

我在我的項目前進,我有另一個像這樣的問題。我做了另一個線程,但如果我只需要編輯第一個線程就告訴我。

我想扭轉我的矩陣。例如[[B,B,N],[N,B,B]]將變爲[[B,N],[B,B],[N,B]]。這裏是我的代碼:

transpose :: Grille -> Grille 
    transpose [] = [] 
    transpose g 
    | head(g) == [] = [] 
    | otherwise = [premierElem(g)] ++ transpose(supp g) 

    supp :: Grille -> Grille 
    supp [] = [] 
    supp (g:xg) = [tail(g)] ++ supp(xg) 

    premierElem :: Grille -> [Case] 
    premierElem [] = [] 
    premierElem (x:xg) = [head(x)] ++ premierElem(xg) 

我得到了完全相同的錯誤,我試圖像第一個,但不是這樣。

編輯:確切的錯誤

*Main> transpose g0 [[B,B,N,B,N,B],[B,B,B,B,N,B],[B,N,N,B,N,B],[B,B,N,N,B,N],[B,N,N,N,B,N],[B,B,N,B,B,B],[N,B,N,N,B,N],[*** Exception: Prelude.head: empty list

+4

你不應該使用tail和head函數,你應該使用模式匹配。例如,在'premierElem g = [head(head(g))]]中,你知道'g'本身是一個非空列表,因爲'premierElem [] = ...'模式在它之前,但是你不知道'head g'是一個非空列表。 'supp g = [tail(head(g))] ...' – user2407038

+0

這是什麼意思?使用模式匹配是什麼意思?我嘗試使用'(g:gx)'來減少'head()'和'tail()'的數量,但它不起作用。對不起,如果我不明白我是初學者。 – pioupiou1211

+0

「我試圖使用(g:gx)」 - 這是正確的,你在正確的軌道上。如果該代碼「不起作用」,請將其包含在問題中,以及它提供給您的錯誤。請注意,您需要嵌套模式,因爲您有一個列表列表 - 例如'transpose([]:xss)= ..;轉置((x:xs):xss)= ...' – user2407038

回答

3

問題是你的transpose函數有一箇中斷的終止條件。它如何知道何時停止?嘗試通過手動完成最後一步...

通常,您的情況transpose [] = []將永遠不會發生,因爲您的supp函數永遠不會更改其參數中列表的數量。格式良好的矩陣將以[[],[],[],...]結尾,這與[]不匹配。唯一會阻止它的是你收到的錯誤。

因此,您需要檢查嵌套(row?)向量的剩餘長度,如果它爲零,則停止。有很多方法可以解決這個問題。如果它沒有作弊,你可以在Prelude文檔中查看transpose的實現。


此外,重新您的評論上面的:如果你希望得到很好的形成,您輸入以某種方式,你應該抱怨的形成不良的輸入,例如報告的error覆蓋任何排除的情況。

+0

的確我沒有注意到這種情況。我不能使用'轉置'(前奏之一)我猜想,因爲這是所有練習的重點。有沒有簡單的方法來做到這一點?我不想僅僅爲此創建其他功能......似乎有點太過分了。有沒有這樣的模式? – pioupiou1211

+0

如果所有嵌套列表的長度應該相同,則可以檢查第一個。這可能更自然地作爲警戒條件,而不是模式匹配。 – comingstorm

+0

哦,是的,謝謝你。我做了這個(看我的第一篇文章的編輯): '轉置::格柵 - >格柵 轉置[] = [] 轉置g \t |頭(g)== [] = [] \t |否則= [premierElem(g)] ++轉置(supp g)' 但我想知道是否有最好的方法來做到這一點?儘管如此,謝謝! – pioupiou1211

2

修復代碼

您應該避免使用部分功能,如尾部和頭部,而是使自己的功能做(更多)模式匹配。例如:

premierElem g = [head(head(g))] ++ premierElem(tail(g)) 

Yuck!如果你想在g第一個列表的第一個元素再搭配上的圖案:

premierElem ((a:_):rest) = [a] ++ premierElem rest 

這本身是不夠的,你要處理的情況下Grille的第一清單的空表,至少給一個有用的錯誤消息,如果你不能用一個合理的默認值:

premeirElem ([]:rest) = premeirElem rest 

製作更好的代碼

最終你會變得更加comfo使用高級操作學會表達自己想要的內容,這通常意味着您可以重用base或其他庫中已提供的功能。在這種情況下:

premeirElem :: [[a]] -> [a] 
premeirElem = concatMap (take 1) 

假定你沒問題,默默地忽略[]。如果這不是你的意圖,那麼其他類似簡潔的解決方案可以很好地工作,但我們需要明確目標。

+0

如果一個空元素實際上是錯誤的,那麼最好使它不可能與例如NonEmpty相比用concatMap寫在它上面並冒着不正確的答案。 – dfeuer

+0

的確,這似乎更好,我做了什麼。我將編輯我的代碼並嘗試熟悉這一點。但事實上,這並不能解決我的錯誤。我不知道它是從哪裏來的,因爲我覆蓋了(我認爲)所有空列表的情況。 – pioupiou1211

+0

@ pioupiou1211您沒有涵蓋所有情況。例如,'premierElem(x:xg)= [head(x)] ++ premierElem(xg)'如果'x == []'會怎麼樣? –