为什么对n级类型需要显式的forall量词?

用户名

当我声明此新类型时:

newtype ListScott a = 
  ListScott { 
  unconsScott :: (a -> ListScott a -> r) -> r -> r 
}

它将定义假设的rank-2类型ListScott :: ((a -> ListScott a -> r) -> r -> r) -> ListScott a,编译器抱怨r不在范围内。从类型签名中是否可以将一流的多态函数传递给我,这不是很明显ListScott吗?

为什么在r这种情况下需要显式类型量词

我不是类型理论家,可能已经忽略了一些东西。

Li-yao Xia

这是编程语言设计的问题。可以按照您的建议进行推断,但是我认为这是一个坏主意。

从类型签名中看不到我想将一流的多态函数传递给ListScott吗?

我认为我们显然不能从这个定义中看出太多。

普遍的还是存在的?与GADT表示法冲突

我们可以使用GADTs扩展名编写以下内容

data ListScott a where
  ListScott :: { unconsScott :: (a -> ListScott a -> r) -> r -> r } -> ListScott a

r是在unconsScott字段中存在地量化的,因此构造函数具有以下第一种类型:

ListScott :: forall a r. ((a -> ListScott a -> r) -> r -> r) -> ListScott a
-- as opposed to
ListScott :: forall a. (forall r. (a -> ListScott a -> r) -> r -> r) -> ListScott a

推理禁用错误检测

r相反,如果if是要作为的参数ListScott,但我们只是忘了添加它,该怎么办?我认为这是一个合理可能的错误,因为假设的ListScott r aListScott a可以在某些方面用作列表的表示。然后,绑定程序的推断将导致错误的类型定义被接受,并且一旦使用了类型,就将在其他位置报告错误(希望不是太远,但这仍然比定义本身的错误更严重)。

显式性还可以防止在类型构造函数被错误键入为类型变量的情况下出现拼写错误:

newtype T = T { unT :: maybe int }
-- unlikely to intentionally mean "forall maybe int. maybe int"

仅类型声明中没有足够的上下文来自信地猜测变量的含义,因此我们应被迫正确地绑定变量。

可读性

考虑功能记录:

data R a = R
  { f :: (r -> r) -> r -> r
  , g :: r -> r
  }

data R r a = R
  { f :: (r -> r) -> r -> r
  , g :: r -> r
  }

我们必须向左看,=以确定是否r绑定到那里,如果不是,我们必须在每个字段中手动插入活页夹。我发现这使第一个版本难以阅读,因为这r两个字段中变量实际上不在同一绑定器下,但是乍一看当然可以看出。

与类似结构的比较

请注意,与您建议的类型类类似的事情发生在类型类上,可以看作一种记录:

class Functor f where
  fmap :: (a -> b) -> f a -> f b

上面的大多数参数同样适用,因此我更愿意将该类编写为:

class Functor f where
  fmap :: forall a b. (a -> b) -> f a -> f b

对于本地类型注释,可以说类似的话。但是,顶级签名不同:

id :: a -> a

id :: forall a. a -> a无疑意味着,因为没有其他层次a可以绑定。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

显式调用`int`析构函数-为什么需要类型别名?

返回兼容类型时,为什么需要显式std :: move?

为什么显式类型转换需要从double到float而不是从int到byte?

为什么在这里需要显式类型参数列表?

为什么C ++和Java中的构造函数调用需要显式类型参数?

为什么基本的Prelude算术不需要显式类型?

为什么我需要在C#显式实现中将'this'转换为接口类型?

为什么IntoIterator特性需要显式指定关联的类型Item?

在更改结果类型时,为什么匹配结果需要显式Err?

为什么 Moq 有时需要在 Returns 中进行显式类型声明?

为什么我得到E2531“方法需要显式类型参数”

为什么在Rust中需要显式的生存期?

为什么Polymer的计算属性需要显式属性参数?

为什么不需要显式设置通用参数?

为什么需要显式推送新分支?

为什么这里不需要显式强制转换?

为什么我需要显式转换泛型调用?

为什么需要显式编写'auto'关键字?

为什么返回Promise时需要显式返回?

为什么在这里需要显式强制转换

为什么Task.FromResult需要显式强制转换?

为什么我需要显式分离短期变量?

为什么显式类型参数应该用菱形替换?

为什么必须显式声明嵌套类型?

为什么我必须显式转换为约束类型?

为什么LINQ的First()需要显式强制转换,而foreach却不需要?

Java何时需要显式类型参数?

为什么F#有两种类型的显式类型声明?

为什么索引显式类型的向量失败并出现类型推断错误?