Data.Proxy的目的是什么? [英] What is the purpose of `Data.Proxy`?
问题描述
数据代理s
何时需要这样的无人居住的类型,它是什么让我无法做到,否则,与其他方法相比,它是什么时候简化了事情?它是如何用于实践的?
我经常在代理
,因为 documentation 指出,以避免不安全地传递虚拟参数。
例如,
data Q
类模数a其中
值: :标记一个Int
实例Modulus Q其中
value = Tagged 5
fxy =(x + y)`mod`(代理值(Proxy :: Proxy Q ))
如果没有 Tagged
,另一种编写方式是
data Q
class Modulus a where
value :: Proxy a - > Int
实例模数Q其中
值_ = 5
fxy =(x + y)`mod`(value(Proxy :: Proxy Q))
在这两个示例中,我们也可以删除 Proxy
类型,只需使用 undefined :: Q
即可传入幻像类型。但是,使用不确定的是一般在因为眉头一皱如果这个价值被评估过,那么问题可能会随之而来。考虑以下几点:
data P =三
|默认
实例模数P其中
值三= 3
值_ = 5
fxy =(x + y)`mod`(value(undefined :: P))
如果我使用默认
构造函数,程序会崩溃,因为我试图评估 undefined
。因此,代理
类型为幽灵类型提供了类型安全性。
编辑
正如Carl指出的那样, Proxy
的另一个好处是可以使用<$ c $以外的幻像类型C> * 。例如,我瞎搞类型列表:
{ - #语言KindSignatures,DataKinds,TypeOperators,
MultiParamTypeClasses,PolyKinds,FlexibleContexts,
ScopedTypeVariables# - }
进口Data.Tagged
进口Data.Proxy
类Foo(A :: [* ])b其中
foo ::标记a [b]
实例Foo'[] Int其中
foo =标记[]
实例Foo xs Int)=> Foo(x':xs)Int其中
foo =标记$ 1:(proxy foo(Proxy :: Proxy xs)) - xs has kind [*]
toUnary :: [ Int]
toUnary = proxy foo(Proxy :: Proxy'[Int,Bool,String,Double,Float])
然而,由于未定义
是一个值,所以它的类型必须是 *
或#
。如果我试图在我的例子中使用 undefined
,我需要类似于 undefined ::'[Int,Bool,String,Double,Float]
$ p
$ OpenKind',
但是'[Int,Bool,String,Double,Float]有'[*]'
欲了解更多信息,请查看此出。鉴于错误消息,我希望能够写入 undefined :: Int#
,但我仍然得到错误 Could not match kind#against *
,所以显然这是一个可怜的GHC错误信息,或者是我的一个简单的错误。
Proxy
from Data.Proxy
seems to be nothing more than a mere
data Proxy s
When do I need such an uninhabited type or rather, what does it enable I couldn't do otherwise, when does it simplify things compared to other approaches, and how is it used in practice?
I frequently use Proxy
with its partner in crime Data.Tagged
, as the documentation indicates, to avoid unsafely passing dummy arguments.
For example,
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))
An alternative way to write that without Tagged
is
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))
In both examples, we could also remove the Proxy
type and just use an undefined :: Q
to pass in the phantom type. However, using undefined is generally frowned upon because of the problems that can ensue if that value is ever evaluated. Consider the following:
data P = Three
| Default
instance Modulus P where
value Three = 3
value _ = 5
f x y = (x+y) `mod` (value (undefined :: P))
which is a valid way to write the instance if I use the Default
constructor, the program would crash since I'm trying to evaluate undefined
. Thus the Proxy
type gives type safety for phantom types.
EDIT
As Carl pointed out, another benefit of Proxy
is the ability to have a phantom type of kind other than *
. For example, I'm messing around with type lists:
{-# 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])
However, since undefined
is a value, its type must have kind *
or #
. If I tried to use undefined
in my example, I'd need something like undefined :: '[Int, Bool, String, Double, Float]
, which results in the compile error:
Kind mis-match
Expected kind `OpenKind',
but '[Int, Bool, String, Double, Float] has kind `[*]'
For more on kinds, check this out. Given the error message, I expected to be able to write undefined :: Int#
, but I still got the error Couldn't match kind # against *
, so apparently this is a case of a poor GHC error message, or a simple mistake on my part.
这篇关于Data.Proxy的目的是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!