我想扩展fst
和snd
的概念以键入类。所以我写了类型类
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
提供了错误数量的参数。我觉得也许一个类型家族可以解决这个问题,但我不知道从哪里开始。
我试图制作一个翻盖,但我也不知道怎么从那里开始。
如何翻转(,)
?
答案 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