[英]Why doesn't this Haskell typeclass code work?
試圖找出Haskell類型類。 為什么以下工作不起作用?
{-# LANGUAGE FlexibleInstances #-}
class IntClass t
instance IntClass Int
intToIntClass :: (IntClass r) => Int -> r
intToIntClass x = x
顯然,“實例”並不代表我認為的含義。 相反,它給出了錯誤消息,我不理解。
Could not deduce (r ~ Int)
from the context (IntClass r)
bound by the type signature for intToIntClass :: IntClass r => Int -> r
at f.hs:10:1-16
`r' is a rigid type variable bound by
the type signature for intToIntClass :: IntClass r => Int -> r
at f.hs:10:1
In the expression: x
In an equation for `intToIntClass t': intToIntClass x = x
簽名
intToIntClass :: (IntClass r) => Int -> r
表示intToIntClass
可以產生調用者想要的任何類型的值,只要該類型屬於IntClass
。 但是實現只能產生Int
值。
就編譯器而言,到目前為止, Int
是唯一的實例並沒有幫助,在其他模塊中可能定義了更多的實例,因此編譯器無法接受僅生成Int
的方法。
您編寫的函數說:“給我點東西,我會把它還給您。” 您寫的類型說:“我可以將Int
轉換為調用者想要的任何類型,只要該類型是IntClass
類型類的實例IntClass
。”
當我們將它們放在一起時,我們有一個函數將從調用方那里獲取一個Int
並將其直接返回。 除了返回相同的Int
以外,它將是調用者希望的任何類型的值,只要該類型是IntClass
類型類的成員IntClass
。 輸入如何從Int
變為調用者想要的任何(受限)類型? 不可以 由於輸入是直接返回的,因此返回類型必須與參數類型相同。 類型檢查器從您的代碼中推斷出這一點,但隨后將其命名為輸出類型r
卻無法調和該推斷。 類型檢查器希望與此一起工作,但是在唯一的假設是r
是IntClass
類型類的實例的情況下,不能確保r
與Int
是同一件事。
類似於您編寫的函數是fromInteger
,位於Num
類型類中。 如果您想討論可以基於Int
構造的所有類型,那么這應該是您的typeclass的方法。 就像是:
class IntClass a where
intToIntClass :: Int -> a
您將為要成為IntClass
實例的每種類型定義此方法,並具有所需的intToIntClass :: IntClass r => Int -> r
。 此返回類型多態性嚴重取決於每個參與類型都具有適當的intToIntClass
定義。
您的類型分類很好。 例如,這有效:
intId :: IntClass r => r -> r
intId = id
問題是, intToIntClass
的類型簽名表明它從Int
映射到IntClass
任何成員。 編譯器無法證明Int
是IntClass
的唯一成員,因此,由於intToIntClass
的主體嚴格返回Int
,因此多態性不夠。
為了進一步說明,假設我將您的模塊與新實例一起使用:
instance IntClass Integer
然后,您對intToIntClass
的實現也承諾具有類型(IntClass Integer => Int -> Integer)
。 但是您的實現與此矛盾。 編譯器假定類型類是“開放的”,這意味着
因此,編譯器認為今天唯一的實例是Int
但不能假設將來會保持這種情況。
(1.)和(2.)的組合使對Haskell代碼的思考和推理更加容易。 當您知道今天的新實例無法破壞昨天的代碼並且今天的代碼對於明天的新實例是安全的時,警告的數量就更少了。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.