如何进行`(,)`的类型级别翻转?

时间:2018-12-07 14:38:03

标签: haskell type-level-computation

我想扩展fstsnd的概念以键入类。所以我写了类型类

class Fstable f where
   fst' :: f a -> a

class Sndable f where
   snd' :: f a -> a

Sndable编写实例非常简单,只需以下内容

instance Sndable ((,) a) where
  snd' (a, b) = b

但是Fstable的实例并不容易。现在,我非常想在flip上使用(,)来创建所需的* -> *。但是类型级别没有翻转功能,因此我必须自己制作或自己制作* -> *

几个月来我没有做过任何类型级别的事情,但是我记得,制作类型级别函数的一种方法是使用FunctionalDependencies。我可以轻松地进行(,)的翻转:

{-# Language MultiParamTypeClases, FunctionalDependcies, FlexibleInstances #-}

class BackTuple a b c | a b -> c

instance BackTuple a b (b, a)

但是BackTuple的类型为* -> * -> * -> Constraint,而不是我想要的* -> * -> *

所以我尝试使用类型同义词

{-# Language TypeSynonymInstances #-}

type W a b = (b, a)

instance Fstable (W a) where
  fst' (a, b) = a

但是我不能这样说,W a抱怨这样一个事实,即不是为W提供了错误数量的参数。我觉得也许一个类型家族可以解决这个问题,但我不知道从哪里开始。

我试图制作一个翻盖,但我也不知道怎么从那里开始。

如何翻转(,)

1 个答案:

答案 0 :(得分:5)

一种选择是使用普通的老式简单类而不是高级的类。例如:

chain.send_keys(line).perform

如果愿意,可以使用类型族完成类似的定义:

class Fstable tuple fst | tuple -> fst where fst' :: tuple -> fst
class Sndable tuple snd | tuple -> snd where snd' :: tuple -> snd

instance Fstable (a,b) a where fst' = fst
instance Sndable (a,b) b where snd' = snd

与原始类兼容的另一种选择是使用新类型翻转参数。与类型别名不同,新类型适用于部分应用程序,因此可以与类型较高的类一起使用。您为此功能付出的代价是在类的每次使用时引入新包装的语法噪音。

class Fstable tuple where type Fst tuple; fst' :: tuple -> Fst tuple
class Sndable tuple where type Snd tuple; snd' :: tuple -> Snd tuple

instance Fstable (a,b) where type Fst (a,b) = a; fst' = fst
instance Sndable (a,b) where type Snd (a,b) = b; snd' = snd