【发布时间】:2021-07-10 14:07:46
【问题描述】:
我一直在为 Javascript 开发一个类型验证器,以便为最初为动态类型设计的语言启用渐进类型。
类型验证意味着只对带有显式类型注释的术语进行类型检查,但没有推理。不幸的是,这种方法是不合理的,因为它允许键入以下程序:
foo :: ([a] -> [a]) -> [b] -> [c] -> ([b], [c])
foo f xs ys = undefined
-- foo f xs ys = (f xs, f ys)
rev :: [d] -> [d]
rev xs = undefined
-- rev = foldl (flip (:)) []
r = foo rev ['a', 'b'] [True, False]
这种类型检查,因为类型推断被绕过。但是,r 没有任何价值,因为函数应用需要更高级别的类型。虽然 Haskell 会在执行 r 的评估后立即终止程序,但在 Javascript 中这样的程序将是有效的,即使我的类型验证器应该拒绝它。
我的第一个想法是分析类型注释并检查函数参数是否与其他参数之一兼容,但这样的方法感觉不对。
是否有更原则性的方法来排除此类类型而不依赖类型推断?
【问题讨论】:
-
如果您不进行类型推断,
foo f xs ys = (f xs, f ys)肯定不应该验证,因为f接受[a]的参数,而您正在传递它[b]和[c],我们不能统一这些类型,因为我们不进行推理? -
即既然你都注释了它们,为什么不允许更高级别的类型,这就是我想说的。我想知道如果您将 all 函数参数视为多态,即将所有高阶函数的类型视为高阶函数,会发生什么?无论如何,您的系统可能更多地处于动态方面。 (我只是在这里大声思考)。
-
我不得不说这个问题我有很多不明白的地方。一些例子:
forall a b c. ([a] -> [a]) -> [b] -> [c] -> ([b], [c])和forall b c. (forall a. [a] -> [a]) -> [b] -> [c] -> ([b], [c])是非常不同的类型,它们都不匹配问题的其余部分。对于第一种类型,应该不可能给r一个通过验证的类型注释,这违反了您的“这种类型检查”断言。对于第二种类型,foo不应通过验证。另一方面,未注释的r首先不需要验证,那你为什么是 1/? -
期望此处显示的代码失败?当然当然未经验证的代码可能会做不合理的事情。 “绕过类型推断并启动惰性评估”是什么意思?类型检查/验证在任何计算开始之前完成;惰性求值,如果它发生的话,会在计算过程中发生。第二个怎么可能导致第一个,当它稍后发生时? “
r没有价值,因为函数应用需要更高级别的类型”是什么意思?为什么更高级别的类型会与评估发生冲突?您的声明“Haskell 在r的 2/? 时立即终止程序? -
执行了评估”,但这...是不正确的。要么它在评估开始之前就被终止,完全独立于
r的评估是否被强制执行,或者它运行完成,即使在r的评估被强制执行之后。所以......在尝试对所有这些不正确的假设/断言进行心理纠正之后,我处于一切看起来都很好和健全的状态(除非没有-type-validated 代码,无法修复),并且完全不确定问题是什么。3/3
标签: haskell type-inference type-systems unification