[英]Enumerating an associated type in a typeclass
給定一個類型類定義,就像下面,我想枚舉MyClassId a
類型的任何類型的實例MyClass
。
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
class
( Enum (MyClassId e)
, Bounded (MyClassId e))
=> MyClass e where
type MyClassId e :: *
enumMyClassId :: MyClass a => [MyClassId a]
enumMyClassId = enumFrom minBound
但是,當我嘗試編譯這段代碼時,GHC 7.10.2會抱怨以下消息:
enumTypeClass.hs:12:18: Couldn't match type ‘MyClassId a0’ with ‘MyClassId a’ NB: ‘MyClassId’ is a type function, and may not be injective The type variable ‘a0’ is ambiguous Expected type: [MyClassId a] Actual type: [MyClassId a0] In the ambiguity check for the type signature for ‘enumMyClassId’: enumMyClassId :: forall a. MyClass a => [MyClassId a] To defer the ambiguity check to use sites, enable AllowAmbiguousTypes In the type signature for ‘enumMyClassId’: enumMyClassId :: MyClass a => [MyClassId a]
我不確定為什么它不能推斷a
類型變量與函數enumMyClassId
的約束中的a
相同。 一種可能的解決方法是將函數enumMyClassId
更改為以下內容:
enumMyClassId :: MyClass a => a -> [MyClassId a]
enumMyClassId _ = enumFrom minBound
但這並不是很優雅,因為它引入了一個未使用的變量,只是為了使程序檢查。 是否有一些解決方案不涉及上述技巧?
您的函數被拒絕的原因是任何使用它的嘗試都會導致歧義。 在使用網站,你可以給限制的簽名MyClassId a
,但你不能指定a
。 您應該能夠通過臨時啟用AllowAmbiguousTypes
將錯誤消息推遲到使用站點(更容易理解)。
有兩個慣用的修復:
enumMyClassId :: MyClass a => proxy a -> [MyClassId a]
您通常會從Data.Proxy
傳遞此Proxy
,但您也可以使用其類型的最后一個參數為a
的任意值。
這種方法通常不太方便,但有時對於記憶事物很重要。
Edward Kmett的tagged
包給你
newtype Tagged s b = Tagged {unTagged :: b}
然后你就寫了
enumMyClassId :: MyClass a => Tagged a [MyClassId a]
並稱之為
enumMyClassId :: Tagged a [MyClassId a]
還有一種GHC特殊的方法,甚至不打算隨身攜帶,但它提供了類似標記類型的性能,並具有代理方便性。
您可以使用GHC在編譯時完全擦除的神奇的Proxy#
類型 。 這就像第一個解決方案一樣,但是使用Proxy# a
類型代替proxy a
。 調用這樣的函數時,你傳遞proxy#
,這是一個完全假的值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.