这只是一个代理。
如果你有
class HasResolution a where
resolution :: Integer
你会被骂,因为编译器无法推断which的实例HasResolution
当你打电话时你想要resolution
。具体来说,resolution :: HasResolution a => Integer
, where a
出现在左边但不在右边,所以你永远无法推断a
.
所以,一种解决方案是
class HasResolution a where
resolution :: a -> Integer
and resolution
的文档会说它并不是为了检查a
;它只是为了让编译器确定选择哪个实例。你可以用它作为resolution (undefined :: a)
。然后,另一个解决方案出现了:
data Proxy a = Proxy
class HasResolution a where
resolution :: Proxy a -> Integer
Proxy
没有提供任何信息resolution
;再次强调,它的存在只是为了让编译器推断出什么a
是。这一点比原版好resolution
really无法检查它的参数,所以Integer
实际上与类型相关联,而不是与参数相关联resolution
。用法更冗长,这有点糟糕(或更好,取决于你问的是谁)resolution (Proxy :: Proxy a)
(你不能只使用undefined
因为实现可能会进行模式匹配Proxy
).
这演变成了
class HasResolution a where
resolution :: p a -> Integer
这意味着您不仅仅局限于Proxy
,这意味着如果您有,例如[a]
位于范围内,您可以将其传递给resolution
不会产生大量冗长的内容,同时保持与刚刚使用的代码的兼容性Proxy
。再次,resolution
的第一个参数仅供编译器使用。对于实际执行来说没有任何意义。您只需使用它来选择实例HasResolution
你要。
Proxy
最终变得如此普遍以至于GHC.Exts
有了新成员:Proxy# https://hackage.haskell.org/package/base/docs/GHC-Exts.html#t:Proxy-35-. Proxy#
没有运行时表示,因此它不会导致性能损失,这与Proxy
(或者上面的多态p
诡计)。Proxy#
然而,它的缺点是它的种类是forall k. k -> TYPE (TupleRep '[])
。由于不住在*
像所有其他“行为良好”的类型一样,它不能参与多态p
trick.
class HasResolution a where
resolution :: Proxy# a -> Integer
第一个解决方案相当过时,尽管有时您会看到示例。第二个和第三个相当常见,第四个很快就被最新的解决方案所取代,该解决方案是启用-XTypeApplications -XAllowAmbiguousTypes
并且只是有
class HasResolution a where
resolution :: Integer
again. -XAllowAmbiguousTypes
避免错误并且-XTypeApplications
让您指定a
在调用站点作为resolution @a
。这不能用在需要一定程度向后兼容的代码中,但你会更多地在需要新 GHC 并且可以承受不兼容的库中看到它。