下面是Haskell函数:
apply_to_f :: (a -> a) -> ((a -> a) -> b) -> ((b -> c) -> c)
apply_to_f f = \ g -> \ h -> h (g f)
字符串
(This来自教会数字的“pred”函数)。
我想告诉编译器一个约束:(apply_to_f f)
可以与自身组合。
换句话说,(apply_to_f f)
接受一个(a -> a) -> a
类型的函数,它也返回一个(a -> a) -> a
类型的函数。
那么,是否有可能告诉编译器,它需要将类型(a -> a) -> b
和(b -> c) -> c
统一为apply_to_f
类型,或者如果我想写下函数的精确类型,我必须自己弄清楚这一点吗?
我最初的猜测是,我也许能够为apply_to_f
编写一个模糊类型,使用类型变量来指示此约束,但这似乎行不通。
1条答案
按热度按时间atmip9wb1#
有几种可能性。首先,你可以将额外的约束表示为类型相等:
字符串
注意,结果类型签名 * 不 * 精确等价于:
型
特别的,GHCi会为这两种类型的签名报告不同的类型,如果
apply_to_f
在"错误类型"使用,报告的错误也会不同。例如,下面的代码类型检查:型
如果您使用直接类型签名限制
apply_to_f
的类型:型
所产生的类型错误将与
foo
的定义中的第二个id
相关联,并将伴随着对第二个id
的预期版本实际类型的清楚解释:型
而如果你使用一个约束:
型
那么类型错误将与
foo
的定义中的apply_to_f
的使用相关联,并且将更模糊地与"foo的推断类型中的一些问题"相关联:型
尽管如此,我认为这两个签名之间的差异在大多数情况下可能是表面上的,它们在实际应用中应该表现得差不多。
其次,您可以利用类型检查器来计算
apply_to_f
的所需类型,方法是强制类型检查器对需要约束的表达式进行类型检查。例如,定义:型
将导致
apply_to_f
的类型被正确推断为:型