[英]Why dollar ($) operator is so complex in GHC 8.0.1?
Prelude> :i ($)
($) ::
forall (r :: GHC.Types.RuntimeRep) a (b :: TYPE r).
(a -> b) -> a -> b
-- Defined in ‘GHC.Base’
infixr 0 $
它与(a -> b) -> a -> b
什么不同? 是否有任何b
不适合新型签名?
8.0之前,有在typechecker的特殊情况做出的应用$
以未提升各项工作。 这也意味着您无法定义自己的功能,这些功能可以同时适用于提升和未提升的类型。 现在这个所谓的Levity Polymorphsim ('levity'指的是'某种程度被解除' - 或'提升',因为'未提升'和'提升'类型)被内置到类型检查器中,这是可能:
import GHC.Exts (TYPE, RuntimeRep(..))
import Data.Kind (type (*))
ap :: forall (a :: *) (b :: *) . (a -> b) -> (a -> b)
ap f x = f x
ap_LP :: forall (a :: *) (b :: TYPE r) . (a -> b) -> (a -> b)
ap_LP f x = f x
实际上$
函数现在与ap_LP
定义相同,在类型检查器中不需要特殊情况来使$
处理返回未提升类型的函数(在类型检查器中仍有一个特殊情况来制作多态应用程序,即runST $ ...
工作,但这是无关的轻率多态性)。 这实际上是增加复杂性的原因 - 现在类型系统中的'黑客'更少,而GHC的用户只需通过给出一个适当类型的函数就可以利用levity多态性(请注意,levity-polymorphic类型永远不会被推断出来) ,据我所知)。 在levity多态之前,如果你想编写一个可能对提升和未提升类型都有效的多态函数,你有义务用不同的类型签名写两个相同的函数副本。
新类型与旧类型的不同之处在于新类型比旧类型更为通用:
-- ok
ap' :: forall (a :: *) (b :: *) . (a -> b) -> (a -> b)
ap' = ap_LP
-- type error:
-- * Couldn't match a lifted type with an unlifted type
ap_LP' :: forall (a :: *) (b :: TYPE r) . (a -> b) -> (a -> b)
ap_LP' = ap
换句话说,每个“适合”旧签名的b
必须(根据定义)适合新类型签名(因此这种改变完全向后兼容!)。
另外请注意,以下是不可能的:
ap'' :: forall (a :: TYPE r) (b :: *) . (a -> b) -> (a -> b)
ap'' f x = f x
产生的错误是
A representation-polymorphic type is not allowed here:
Type: a
Kind: TYPE r
In the type of binder `x'
和SPJ在这里解释限制的原因:
($)的第二个参数必须没有未装箱的类型,这是绝对正确的。 因为($)的代码必须移动该参数(传递给函数),所以它必须知道它的宽度,指针等。
但实际上,调用(f $ x)的结果是可以取消装箱的,因为($)的代码不会弄乱结果; 它只是尾巴调用f。
这就是说,并非每个levity-polymorphic类型都有一个有效的居民 - 这与未装箱和盒装类型之间的操作区别有关,只能在某些情况下统一处理,而typechecker会确定它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.