簡體   English   中英

Haskell - “應用程序中的類型錯誤”:“統一會給出無限類型”

[英]Haskell - “Type error in application”: “unification would give infinite type”

我正在開始使用Haskell,但是我試圖制作的這種平等檢查並沒有成功。

我有一個函數countLetter a [b] c ,其中a是char, b是chars列表, c是int。 (類型聲明通過罰款。)但是我遇到了這個表達式的問題:

if a == head(b)

給我以下消息:

Type error in application

*** Expression     : a == head b
*** Term           : a
*** Type           : [a]
*** Does not match : a
*** Because        : unification would give infinite type

如果需要,我的代碼是完整的:

countLetter :: char -> [char] -> int

countLetter a [b] c = if null b

                       then []
                       else
                       if a == head(b)
                       then countLetter a tail(b) c+1
                    else
                    countLetter head(b) tail(b) c

任何幫助或建議將不勝感激。 謝謝。

首先,Haskell中的類型以大寫字母開頭。 如果在類型簽名中使用以小寫字母開頭的標識符,則將它們解釋為類型變量。 所以你的類型char -> [char] -> inta -> [a] -> b ,這對你的函數來說不是一個合理的類型。 你想要的Char -> [Char] -> Int

其次, []不是Int類型的有效值。 修復您的類型簽名應該會產生一條錯誤消息,告訴您不那么模糊的術語。

然后,它也應該告訴你, null b是一種錯誤,因為b是類型的Char (你的函數的第二個參數是類型[Char]與你匹配它與模式[b]結合b的單包含在該列表中的Char )和null將列表而不是Char作為其參數。

最后一點澄清:

函數的第二個參數是一個列表。 通過在參數列表中編寫[b] ,可以將該參數與模式[b]匹配。 換句話說,寫countLetter a [b] c = blabla與寫入相同:

countLetter a theList c =
    case theList of
        [b] -> blabla

所以你要說:“函數的第二個參數必須是一個包含一個元素的列表,該元素應該被稱為b ”。 這不是你想要說的。 你想要說的是“函數的第二個參數(順便提一下,它是一個列表)應該被稱為b ”。 為此,你只需寫入countLetter abc = blabla

類型列表的參數不必以與其他類型的參數不同的方式表示。

您將遇到的另一個錯誤是:

countLetter head(b) tail(b) c

按照規則,這是相同的

countLetter head b tail b c

即你只用3個參數調用你的countLetter函數,當它只需要3個(根據第一個等式)或2個(根據你的類型簽名)。 (這是編譯器非常不滿意的另一點。)

你可能想要這個:

countLetter (head b) (tail b) c

同樣:

countLetter a tail(b) c+1

是相同的

(countLetter a tail b c) + 1

但你可能想要:

countLetter a (tail b) (c+1)

除了提供修復函數的其他答案之外,您可能還需要考慮以更具成分的方式編寫它。 具體來說,通過構建其他標准函數來尋找編寫函數的方法。 假設您有一個函數將刪除與列表中的測試字母不相等的所有內容。

myFilter :: Char -> [Char] -> [Char
myFilter = ...

使用myFilter ,您將只剩下一個列表,其中只包含您要檢查的元素。 此時,您可以使用length來獲取列表的長度:

countLetter :: Char -> [Char] -> Int
countLetter a b = length $ myFilter a b

所以現在你只需要定義myFilter ,這可以使用標准的Prelude函數filter來完成

myFilter a b = filter (==a) b

對於一個小的函數,創建我們自己的定義幾乎不值得,因為你可以寫

countLetter a b = length $ filter (== a) b

現在,在ghci中定義它以查看它為函數countLetter找到的類型

Prelude> let countLetter a b = length $ filter (== a) b
Prelude> :t countLetter
countLetter :: Eq a => a -> [a] -> Int

看見沒有Char 實現不依賴於元素是字母,只是可以比較它們的相等性(這也適用於您的方法)。 所以ghci在計算的類型中反映出來。 但你可以通過用Char代替a來看到這正是你想要的類型。

許多功能程序員傾向於找到這種方法,即通過組合較小的部件來構建功能,特別容易推理,因此它很常見。 特別是在使用列表時,您可能希望查看是否可以使用所謂的高階函數(例如mapfilter或fold)編寫實現,而不是使用遞歸。 有時遞歸是最清晰的方式,但我希望你經常會發現函數組合是一種更好的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM