在 class 个实例中需要更高种类的类型

Require higher kinded type in class instances

我有一个看起来像这样的类型。

data State = Unsanitized | Sanitized

type family BarTy (s :: State) :: Type where
  BarTy 'Unsanitized = String
  BarTy 'Sanitized = Int

data Foo (a :: State) = Foo (Bar a)
data Bar (a :: State) = Bar (BarTy a)

我使用类型参数来更改某些字段的类型。这在通过验证管道演进数据结构时很有用。

现在我想写一个 class 可以从这个数据结构中提取一些东西,但它是哪个 State 并不重要。完整示例:

data State = Unsanitized | Sanitized

type family BarTy (s :: State) :: Type where
  BarTy 'Unsanitized = String
  BarTy 'Sanitized = Int

data Foo (a :: State) = Foo (Bar a)
data Bar (a :: State) = Bar (BarTy a)

class Extractor a where
  extract :: a -> (BarTy b)

instance Extractor (Foo a) where
  extract (Foo x) = extract x

instance Extractor (Bar a) where
  extract (Bar x) = x

这显然是行不通的,因为 b 类型变量在实例中总是未知的,因此会发生类型错误。我可以制作另一个类型族,从给定类型中提取 State 类型,但这对于较大的类型来说确实很笨重。

data State = Unsanitized | Sanitized

type family BarTy (s :: State) :: Type where
  BarTy 'Unsanitized = String
  BarTy 'Sanitized = Int

type family ExtractState (t :: Type) :: State where
  ExtractState (Foo s) = s
  ExtractState (Bar s) = s
  ExtractState _ = TypeError ('Text "ExtractState: Passed type is not valid.")

data Foo (a :: State) = Foo (Bar a)
data Bar (a :: State) = Bar (BarTy a)

class Extractor a where
  extract :: a -> (BarTy (ExtractState a))

instance Extractor (Foo a) where
  extract (Foo x) = extract x

instance Extractor (Bar a) where
  extract (Bar x) = x

bar1 :: Bar 'Unsanitized
bar1 = Bar "Test"
foo1 = Foo bar1

bar2 :: Bar 'Sanitized
bar2 = Bar 1337
foo2 = Foo bar2

a = extract bar1
b = extract foo1
c = extract bar2
d = extract foo2

我最想做的是在 class 声明中进行模式匹配,但我不知道该怎么做,甚至不知道是否可行:

data State = Unsanitized | Sanitized

type family BarTy (s :: State) :: Type where
  BarTy 'Unsanitized = String
  BarTy 'Sanitized = Int

data Foo (a :: State) = Foo (Bar a)
data Bar (a :: State) = Bar (BarTy a)

class Extractor (t a) where
  extract :: (t a) -> (BarTy a)

instance Extractor (Foo a) where
  extract (Foo x) = extract x

instance Extractor (Bar a) where
  extract (Bar x) = x

可以Haskell做这样的事情吗?还是有其他方法可以实现我想要的?

感谢任何帮助。

请记住,您可以在定义类型类时部分应用类型:

class Extractor t where
    extract :: t a -> BarTy a

(在 FunctorApplicativeMonad 的定义中使用了相同的技术,并且通常几乎所有类型类都用于更高类型的类型。)