簡體   English   中英

類型族中的多態函數

[英]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"

您需要啟用一些擴展: MultiParamTypeClassesTypeSynonymInstancesFlexibleInstances (后兩者僅因為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.

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