Data.Proxy
中的Proxy
似乎只是一个简单的东西。
data Proxy s
我何时需要这种无人居住的类型,或者说,它能够让我做什么,否则我不能做什么,与其他方法比较简化了什么,以及它在实践中如何使用?
Data.Proxy
中的Proxy
似乎只是一个简单的东西。
data Proxy s
我何时需要这种无人居住的类型,或者说,它能够让我做什么,否则我不能做什么,与其他方法比较简化了什么,以及它在实践中如何使用?
Proxy
)及其搭档 Data.Tagged
,正如文档所述,以避免不安全地传递虚拟参数。
例如,
data Q
class Modulus a where
value :: Tagged a Int
instance Modulus Q where
value = Tagged 5
f x y = (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
f x y = (x+y) `mod` (value (Proxy::Proxy Q))
Proxy
类型并仅使用undefined :: Q
来传递幽灵类型。但是,由于如果评估该值可能会出现问题,使用undefined通常会受到反对。请考虑以下情况:(原文链接详见此处)data P = Three
| Default
instance Modulus P where
value Three = 3
value _ = 5
f x y = (x+y) `mod` (value (undefined :: P))
Default
构造函数,写下实例的方式是有效的,但程序会崩溃,因为我试图评估undefined
。因此,Proxy
类型为幻像类型提供了类型安全性。Proxy
的另一个好处是能够具有除*
以外的其他种类的幻像类型。例如,我正在处理类型列表:{-# 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
是一个值,其类型必须具有*
或#
的种类。 如果我尝试在我的示例中使用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 错误消息不够清晰,或者是我的一个简单错误。
Proxy
也支持多态种类。你可以这样说 Proxy :: Proxy Maybe
。祝你好运尝试表达 undefined :: Maybe
。 - CarlProxy
比使用undefined
更安全有显著的差异。当然,这并不会削弱这个答案的价值。 - John Lproxy
而不是 unTagged
? - copprounTagged
。 - crockeea
Proxy s
不是一个无人居住类型,它有一个单一的构造函数Proxy
。 - Cactus