[英]Polymorphic function inside a type family
我試圖在一個類型系列中定義一個函數,該函數在類型族中定義的幻象類型的GADT本身是多態的。
我的類型系列定義如下:
class Channel t where
data Elem t a :: *
foo :: t -> Elem t a
bar :: Elem t a -> [a]
我有一個實例如下:
data MyChannelType = Ch
instance Channel MyChannelType where
data Elem MyChannelType a where
MyConstructor :: Char -> Elem MyChannelType Char
foo _ = MyConstructor 'a'
bar (MyConstructor c) = repeat c
編譯器抱怨說:
Couldn't match type ‘a’ with ‘Char’
‘a’ is a rigid type variable bound by
the type signature for foo :: MyChannelType -> Elem MyChannelType a
是否可以使用Rank2Types編寫此函數或重新配置我的數據類型以啟用它?
編輯 :回應Ganesh要求的澄清
我希望foo (bar Ch) :: [Int]
是非法的。
我一直在使用完全解決方案Ganesh神暗示,但我按下面的更復雜的例子,在那里倒下的動機; 給定:
data MyOtherType = IntCh | StringCh
我有一個實例如下:
instance Channel MyOtherType where
data Elem MyOtherType a where
ElemInt :: Int -> Elem MyOtherType Int
ElemString :: String -> Elem MyOtherType String
foo IntCh = ElemInt 0
foo StringCh = ElemString "a"
bar (ElemInt i) = repeat i
bar (ElemString s) = repeat s
非常感謝,
邁克爾
隨着你給的簽名, foo
是不可實現的MyChannelType
因為它聲稱能夠產生Elem MyChannelType a
對任何a
類型。
如果您真正想要的是給定t
只應該有a
類型,您可以使用類型函數來表達:
class Channel t where
data Elem t a :: *
type Contents t :: *
foo :: t -> Elem t (Contents t)
bar :: Elem t a -> [a]
然后添加
type Contents MyChannelType = Char
到實例。
為了回應您的編輯,我將Channel
分為兩類:
class Channel t where
data Elem t a :: *
bar :: Elem t a -> [a]
class Channel t => ChannelContents t a where
foo :: t -> Elem t a
然后,您可以使用以下命令定義MyOtherType
實例:
instance Channel MyOtherType where
data Elem MyOtherType a where
ElemInt :: Int -> Elem MyOtherType Int
ElemString :: String -> Elem MyOtherType String
bar (ElemInt i) = repeat i
bar (ElemString s) = repeat s
instance ChannelContents MyOtherType Int where
foo IntCh = ElemInt 0
instance ChannelContents MyOtherType String where
foo StringCh = ElemString "a"
您需要啟用一些擴展: MultiParamTypeClasses
, TypeSynonymInstances
, FlexibleInstances
(后兩者僅因為String
實例)。
至於Ganesh的解決方案更廣泛的選擇,你也可以約束a
變量來一整類的類型(可能只是一個單一的一個):
{-# LANGUAGE ConstraintKinds #-}
import GHC.Exts (Constraint)
class Channel t where
data Elem t a :: *
type ElemConstraint t a :: Constraint
foo :: ElemConstraint t a => t -> Elem t a
bar :: ElemConstraint t a => Elem t a -> [a]
instance Channel MyChannelType where
data Elem MyChannelType a where
MyConstructor :: Char -> Elem MyChannelType Char
type ElemConstraint t a = a ~ Char
foo _ = MyConstructor 'a'
bar (MyConstructor c) = repeat c
class OtherType_Class c where
mkOtherTypeElem :: c -> Elem MyOtherType c
evOtherTypeElem :: Elem MyOtherType c -> c
instance OtherType_Class Int where
mkOtherTypeElem = ElemInt
evOtherTypeElem (ElemInt i) = i
instance OtherType_Class String where
...
instance Channel MyOtherType where
data Elem MyOtherType a where
ElemInt :: Int -> Elem MyOtherType Int
ElemString :: String -> Elem MyOtherType String
type ElemConstraint MyOtherType a = OtherType_Class a
但是,我應該說,對於一些固定的類型集合來說,這是一個相當尷尬的事情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.