当我声明此新类型时:
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
这种情况下需要显式类型量词?
我不是类型理论家,可能已经忽略了一些东西。
这是编程语言设计的问题。可以按照您的建议进行推断,但是我认为这是一个坏主意。
从类型签名中看不到我想将一流的多态函数传递给ListScott吗?
我认为我们显然不能从这个定义中看出太多。
我们可以使用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 a
和ListScott 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] 删除。
我来说两句