我正在试图弄清楚是否有可能(以及如何)为多参数类型同义词定义类实例。
例如:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}
type F a b = a -> b
data DF a b = DF (a -> b)
class C c a b where
doc :: c a b -> a -> b
适用于多参数类型的实例:
instance C DF a b where
doc (DF f) x = f x
但它不适用于类型同义词:
-- ERROR:
--
-- Type synonym `F' should have 2 arguments, but has been given none
-- In the instance declaration for `C F a b'
--
instance C F a b where
doc f x = f x
是否可以为F
?
答案 0 :(得分:16)
这不可能是书面的。类型同义词通常必须完全应用才能使用它们,尤其是as a type class parameter。
请注意,如果您可以eta-reduce类型同义词,则可以使用实例;它是必须完全应用的同义词,而不是它所指的类型。所以这会奏效:
type F = (->)
instance C F a b where
doc f x = f x
关于扩展类型同义词有a LiberalTypeSynonyms
extension that relaxes some of the rules,但它在这里没有帮助 - 它只允许你做一些事情,比如将部分应用的类型同义词作为另一个类型同义词的类型参数。一切都必须完全扩展到其他方面。
要查看为什么需要此限制的一个原因,请考虑以下类型的同义词:
type Flip f a b = f b a
以下实例:
instance Functor (Flip Either a) where
fmap _ (Right x) = Right x
fmap f (Left x) = Left (f x)
回想一下,除了镜像之外,还有一个实例Functor (Either a)
执行相同的操作。两者都是明智的Functor
个实例。
请注意,与newtype
不同,类型同义词被认为与它们引用的类型相同,表达式fmap not (Right True :: Either Bool Bool)
的值应该是什么?
答案 1 :(得分:3)
必须完全应用类型同义词才能为它们定义实例。正如人们所期望的那样,F
的类型不是* -> * -> *
,而是在提供两个以上的类型参数之前无效。尝试
type F = (->)
代替。