繁体   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