10

我试图弄清楚是否可以(以及如何)为多参数类型同义词定义类实例。

例如:

{-# 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

4

2 回答 2

15

这是不可能的。类型同义词通常必须完全应用才能使用它们,尤其是作为类型类参数

请注意,如果您可以对类型同义词进行足够的 eta-reduce,则一个实例是可能的;它是必须完全应用的同义词,而不是它所指的类型。所以这会起作用:

type F = (->)

instance C F a b where
    doc f x = f x

一个LiberalTypeSynonyms扩展放宽了一些关于扩展类型同义词的规则,但它在这里没有帮助——它只允许你做一些事情,比如将一个部分应用的类型同义词作为另一个类型同义词的类型参数。一切都必须完全扩展才能使用。

要了解为什么需要此限制的一个原因,请考虑以下类型同义词:

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)是什么?

于 2013-04-17T12:37:37.580 回答
3

必须完全应用类型同义词才能为它们定义实例。正如人们所期望的那样,这种F不是* -> * -> *,而是在提供另外两个类型参数之前无效。尝试

type F = (->)

反而。

于 2013-04-17T12:38:07.720 回答