为啥我只能在类型参数位置传递部分应用的类型构造函数?

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 应用于aa b 会导致 kind 错误并因此被拒绝,这是完全有道理的。但是为什么foo 被接受了呢?

【问题讨论】:

t 可以有种类(* -> *) -> *,所以执行到具体类型的映射。对于不可能的列表,因为该列表具有类型 * -> *,因此这意味着 f a 应该是“具体”类型。 考虑data T container = T (container Int) (container String),它是容器类型的参数类型,它包含一个内部带有Ints 的容器和一个内部带有Strings 的容器,以及type F = (,),一个容器系列,每个元数据类型一个,用一些元数据标记单个包含的元素。 如果你听说过monad转换器,你需要能够做到这一点。如果不是,基本上它们将任意 monad 转换为具有附加功能的新 monad(在 Haskell 中构建复杂代码的一种相当常见的模式是将多个 monad 转换器堆叠在一起)。为此,他们需要将 monad 本身作为类型参数,而不是应用的 monadic 类型(例如,他们需要采用 MaybeIOState s 等;而不是 Maybe IntIO 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 很高兴被接受。

以上是关于为啥我只能在类型参数位置传递部分应用的类型构造函数?的主要内容,如果未能解决你的问题,请参考以下文章

为啥为非泛型方法或构造函数提供显式类型参数会编译?

Oracle PL/SQL 传递行类型作为构造函数参数

为啥在传递 long long 时调用具有两个 double 类型参数的重载函数?

c++中如何用函数传递fstream类型

java中方法传递参数为啥可以不用基本数据类型

java 怎么往构造函数里面传递参数