Haskell 为什么参数化类型实例在不指定类型参数的情况下工作

Haskell 为什么参数化类型实例在不指定类型参数的情况下工作,haskell,typeclass,type-parameter,Haskell,Typeclass,Type Parameter,具有参数化类型时: 数据A=X A|Y 我已尝试(成功)实现Functor和Applicative,但未指定类型参数: 实例函子A where而不是实例函子(A)where它为什么工作查看,似乎所有示例都在其类型类实例中指定了类型参数。 什么时候应该忽略类型参数 什么时候应该忽略类型参数 > :k Eq Eq :: * -> Constraint 类型参数不是“忽略”的。让我们首先看看函子类型类: class Functor f where fmap :: (a ->

具有参数化类型时:
数据A=X A|Y

我已尝试(成功)实现
Functor
Applicative
,但未指定类型参数:

实例函子A where
而不是
实例函子(A)where

它为什么工作

查看,似乎所有示例都在其
类型类实例中指定了类型参数。
什么时候应该忽略类型参数

什么时候应该忽略类型参数

> :k Eq
Eq :: * -> Constraint
类型参数不是“忽略”的。让我们首先看看
函子
类型类:

class Functor f where
    fmap :: (a -> b) -> f a -> f b
因此,我们从以下几点开始:

  instance Functor Maybe where
然后执行
fmap
。所有类型参数加起来是因为
可能
取代了中的
f
Functor
type类的定义,如果我们看
fmap
就像它只在
上起作用一样,它最终的行为类似于:

fmap :: (a -> b) -> Maybe a -> Maybe b
(……)

实例函子A where
而不是
实例函子A where
。 它为什么有效

我发现使用GHC的火种系统更容易理解这一点。让我们从一个简单的案例开始,在GHCi中进行实验:

> :k Eq Int
Eq Int :: Constraint
这告诉我们,
Eq Int
是一个约束,一些属性可能在类型检查期间得到验证。实际上,如果我们键入check
(12::Int)==(42::Int)
,编译器将验证可以比较整数,从而解析约束
Eq Int

什么是
Eq
,没有
Int
参数的类的名称

> :k Eq
Eq :: * -> Constraint
这告诉我们,
Eq
可以看作是从类型(
*
是类型的一种)到约束的函数

事实上,在
Eq Int
中,
Int
是一种类型,因此我们有
Int:*
使
Int
成为传递给
Eq
的类似参数

足够的类型类,那么类型构造函数呢

> :k Maybe Int
Maybe Int :: *
毫不奇怪,
可能Int
是一种类型

> :k Maybe
Maybe :: * -> *
可能是一个从类型到类型的函数(
*->*
)。这确实是
Maybe
类型构造函数所做的:将一个类型(
Int
)映射到一个类型(
Maybe Int

回到原来的问题。为什么我们不能写
实例函子(A)
,但我们可以写
实例函子A
?嗯,我们有

> :k A Int
A Int :: *
> :k A
A :: * -> *
最重要的是

> :k Functor
Functor :: (* -> *) -> Constraint
这告诉我们
函子
类型类的类型与
Eq
类型类的类型不同
Eq
需要一个类型作为参数,而
Functor
需要某种类型的
(*->*)
作为参数
A
适合这种类型,而
A Int
不适合这种类型

在类的定义中,当参数应用于其他类型时,就会发生这种情况。例如

class C1 a where
   foo :: a -> Bool
结果为
C1::*->约束
。相反

class C2 f where
   bar :: f Int -> Bool

结果在
C2::(*->*)->约束
,因为
f
本身不是一个类型,
f Int
是,所以
f
必须是一种参数化类型
*->*

fmap
的类型签名(在
函子中
fmap::(a->b)->fa->fb
,因此这里我们将
a
应用于类型构造函数
a
,假设我们将
a Int
作为函子,我们应该如何处理
fa
(因此
a Int a
)?因此类型参数不会被“忽略”,这里的
f
基本上是一个接受类型并构造新类型的函数。@BercoviciAdrain:没错,
f
是一个将类型(如
Int
)转换为类型
Int
的“函数”。我们只需传递一个构造类型的函数。然后类型类本身就可以“构造类型”例如,它可以做一些类似于
otherfmap::(Int->String)->f Int->f String
,因此参数本身不是自由的,但是对于
Functor
,它是自由的。是的,但是类型构造函数是“类型级别”上的函数,就像数据构造函数是“实例级别”上的函数一样。