Data.Proxy的目的是什么?
从Data.Proxy
Proxy
似乎只不过是一个单纯的
data Proxy s
我什么时候需要这样一种无人居住的types,或者说是什么使我无法做到的,什么时候与其他方法相比简化了事情,它是如何在实践中使用的?
我经常使用Proxy
与犯罪Data.Tagged
伙伴,如文档指出,以避免不安全地传递虚拟参数。
例如,
data Q class Modulus a where value :: Tagged a Int instance Modulus Q where value = Tagged 5 fxy = (x+y) `mod` (proxy value (Proxy::Proxy Q))
另一种方式来写没有Tagged
是
data Q class Modulus a where value :: Proxy a -> Int instance Modulus Q where value _ = 5 fxy = (x+y) `mod` (value (Proxy::Proxy Q))
在这两个例子中,我们也可以删除Proxy
types,只需使用undefined :: Q
来传入幻像types。 然而,使用未定义通常是不被接受的,因为如果这个价值被评估过,那么可能会出现问题。 考虑以下:
data P = Three | Default instance Modulus P where value Three = 3 value _ = 5 fxy = (x+y) `mod` (value (undefined :: P))
这是一个有效的方法来编写实例, 如果我使用Default
构造函数 ,程序会崩溃,因为我试图评估undefined
。 因此, Proxy
types为幻像types提供types安全性。
编辑
正如Carl指出的那样, Proxy
另一个好处是能够拥有除*
以外的幽灵types。 例如,我正在搞types列表:
{-# LANGUAGE KindSignatures, DataKinds, TypeOperators, MultiParamTypeClasses, PolyKinds, FlexibleContexts, ScopedTypeVariables #-} import Data.Tagged import Data.Proxy class Foo (a::[*]) b where foo:: Tagged a [b] instance Foo '[] Int where foo = Tagged [] instance (Foo xs Int) => Foo (x ': xs) Int where foo = Tagged $ 1 : (proxy foo (Proxy :: Proxy xs)) -- xs has kind [*] toUnary :: [Int] toUnary = proxy foo (Proxy :: Proxy '[Int, Bool, String, Double, Float])
但是,因为undefined
是一个值 ,所以它的types必须有*
或#
。 如果我试图在我的例子中使用undefined
,我需要像undefined :: '[Int, Bool, String, Double, Float]
,这会导致编译错误:
Kind mis-match Expected kind `OpenKind', but '[Int, Bool, String, Double, Float] has kind `[*]'
有关更多种类,请检查此 。 鉴于错误消息,我希望能够写入undefined :: Int#
,但我仍然得到错误Couldn't match kind # against *
,显然这是一个糟糕的GHC错误信息,或一个简单的错误对我而言。