为啥我只能在类型参数位置传递部分应用的类型构造函数?
Posted
技术标签:
【中文标题】为啥我只能在类型参数位置传递部分应用的类型构造函数?【英文标题】:Why can I pass partially applied type constructors only in type parameter position?为什么我只能在类型参数位置传递部分应用的类型构造函数? 【发布时间】:2021-11-05 13:22:59 【问题描述】:这可能是一个愚蠢的问题,但我无法弄清楚以下行为的基本规则:
foo :: t (f a) -> f a b -- accepted
foo = undefined
bar :: t [f a] -> f a b -- rejected
bar = undefined
在bar
中分别将f
应用于a
和a b
会导致 kind 错误并因此被拒绝,这是完全有道理的。但是为什么foo
被接受了呢?
【问题讨论】:
t
可以有种类(* -> *) -> *
,所以执行到具体类型的映射。对于不可能的列表,因为该列表具有类型 * -> *
,因此这意味着 f a
应该是“具体”类型。
考虑data T container = T (container Int) (container String)
,它是容器类型的参数类型,它包含一个内部带有Int
s 的容器和一个内部带有String
s 的容器,以及type F = (,)
,一个容器系列,每个元数据类型一个,用一些元数据标记单个包含的元素。
如果你听说过monad转换器,你需要能够做到这一点。如果不是,基本上它们将任意 monad 转换为具有附加功能的新 monad(在 Haskell 中构建复杂代码的一种相当常见的模式是将多个 monad 转换器堆叠在一起)。为此,他们需要将 monad 本身作为类型参数,而不是应用的 monadic 类型(例如,他们需要采用 Maybe
、IO
、State s
等;而不是 Maybe Int
、IO String
,或State s ()
)。
【参考方案1】:
是f
的那种。
由于返回类型是f a b
- 即f
应用于两个参数, - 这意味着f :: Type -> Type -> Type
。
但是然后f a
被用作列表元素——[f a]
——并且列表元素必须是Type
,即f a :: Type
,即f :: Type -> Type
。
不匹配。
foo
之所以有效,是因为可以部分应用类型。也就是说,如果f :: Type -> Type -> Type
,那么f a :: Type -> Type
。然后,类型t
允许有一个Type -> Type
类型的参数,所以一切都匹配。
重申上述内容:
foo
有效,因为类型 t
可能有一个类型为 Type -> Type
的参数。
bar
不起作用,因为类型 []
(又名“列表”)必须有一个类型为 Type
的参数。
【讨论】:
在术语级别上,您不能将函数参数传递给一阶函数。同样的原则也适用于类型级别。我预计这将是一个愚蠢的问题。这都是关于种类的:foo :: t f -> t (->) -> f a b
很高兴被接受。以上是关于为啥我只能在类型参数位置传递部分应用的类型构造函数?的主要内容,如果未能解决你的问题,请参考以下文章