Haskell 反转类型族

Haskell 反转类型族,haskell,type-families,Haskell,Type Families,我有一个“线性”类型的族,即形式 type family Foo a type instance Foo T1 = T2 type instance Foo T2 = T3 ... type instance Foo T9 = T10 在我的特定用例中,定义“反向”族FooRev,然后强制执行约束(FooRev(Foo x)~x),非常方便: 反向族允许GHC推断出许多类型,否则由于非注入性,这些类型将是不明确的。这基本上与提出的想法相同。这个解决方案工作得很好,但它很烦人,编程性强,并且容易

我有一个“线性”类型的族,即形式

type family Foo a
type instance Foo T1 = T2
type instance Foo T2 = T3
...
type instance Foo T9 = T10
在我的特定用例中,定义“反向”族
FooRev
,然后强制执行约束
(FooRev(Foo x)~x)
,非常方便:


反向族允许GHC推断出许多类型,否则由于非注入性,这些类型将是不明确的。这基本上与提出的想法相同。这个解决方案工作得很好,但它很烦人,编程性强,并且容易出错,必须通过列出所有情况来定义“反向”类型族。是否有一种更通用的方法来定义线性族的反面,例如
Foo

我认为
功能依赖性
应该是您案例的最佳解决方案:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}

class Foo a b | a -> b, b -> a
instance Foo T1 T2
instance Foo T2 T3
...

现在,每个
b
都可以从
a
中推断出来,反之亦然

我决定尝试一下@chi的想法,但最后我想出了一个更简单的办法

{-# LANGUAGE TypeOperators, DataKinds, TypeFamilies #-}

type family NextElt (a :: *) (xs :: [*]) where
  NextElt a (a ': b ': cs) = b
  NextElt a (b ': c ': cs) = NextElt a (c ': cs)

type family PrevElt (a :: *) (xs :: [*]) :: * where
  PrevElt a (b ': a ': xs) = b
  PrevElt a (b ': c ': xs) = PrevElt a (c ': xs)

data T1
data T2
data T3
type TSeq = '[T1, T2, T3]

type NextRp a = NextElt a TSeq
type PrevRp a = PrevElt a TSeq

使用类型列表来表示类型的线性序列允许我表达关系,而无需两次写入每个类型(这是使用类型族实例或类实例所必需的)。上面的类型族使用滑动窗口方法在包含上一个或下一个元素的列表中搜索元素。这些类型族是泛型的(并且可以通过使用扩展为适用于非
*
类型)。

也许您可以使用
数据
族来代替,这些族是已知的内射族。不确定它是否适合您的问题。元编程(即模板Haskell)可能会同时生成这两种代码,如果您担心的话,可以保持代码干燥。否则,您可以定义一个类型级关联列表、一个类型级查找、一个类型级
映射交换
,并从列表中派生两个类型族。@luqui我在发布之前就看到了这一点,但据我所知,这并不是我真正需要的。在我的例子中,
Ti
都是类型
Bar a b c
,其中类型参数发生变化。这不适合数据家族,是吗?@chi也许你可以演示其中一个想法?
{-# LANGUAGE TypeOperators, DataKinds, TypeFamilies #-}

type family NextElt (a :: *) (xs :: [*]) where
  NextElt a (a ': b ': cs) = b
  NextElt a (b ': c ': cs) = NextElt a (c ': cs)

type family PrevElt (a :: *) (xs :: [*]) :: * where
  PrevElt a (b ': a ': xs) = b
  PrevElt a (b ': c ': xs) = PrevElt a (c ': xs)

data T1
data T2
data T3
type TSeq = '[T1, T2, T3]

type NextRp a = NextElt a TSeq
type PrevRp a = PrevElt a TSeq