你如何从代理中提取类型信息? [英] How can you extract type information from a Proxy?

查看:115
本文介绍了你如何从代理中提取类型信息?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有一个标准的代理

a>某些类型 a 隐藏在内部:

  pxyA = Proxy: :代理a 

由于我的程序的其他部分,我知道一个事实,即 a 实际上是另外两种类型的元组,例如(b,c)。有什么办法让我从我的原始代理中提取这样的信息:

  f :: Proxy a  - > ; (代理b,代理c)



  f :: Proxy a  - >代理(b,c)

阻止我的主要原因是我不知道类型 b c 将会是,我需要将它们传递给我的程序的其他部分。



我已经写了一个类似形式的简单函数:

  splitPxyTup :: forall ab。代理(a,b) - > (Proxy a,Proxy b)
splitPxyTup _ =(Proxy :: Proxy a,Proxy :: Proxy b)

但是如何说服类型系统,我的原始代理实际上是一个元组类型,不断迷路。



我也考虑过使用 cast ,但由于我不知道输出类型是什么,

解决方案

我一直在试着去看看你在做什么,如果你能够生成一个代表你的问题的更完整的例子,这将是有帮助的。



在那之前,我似乎对这部分您的问题


阻止我的主要原因是我不知道类型 b c 将会是...


这句话听起来像你需要一个存在:

  proxyTuple :: Proxy a  - >存在b c。代理(b,c)

这是无效的Haskell,但我们可以很容易地对它进行编码: p>

  data ProxyTupleEx其中
ProxyTupleEx :: Proxy(b,c) - > ProxyTupleEx

虽然这还不够,因为我们可以很轻松地实现这个功能。

  proxyTuple :: Proxy a  - > ProxyTupleEx 
proxyTuple _ = ProxyTupleEx(Proxy :: Proxy((),()))

我们还需要指定与传入 a 的连接。我们可以这样做:

  data ProxyTupleEx a where 
ProxyTupleEx ::(a〜(b,c))= >代理(b,c) - > ProxyTupleEx a

我们将无法实现 proxyTuple 现在,因为当 a 不是元组时它没有实现。我们需要

  proxyTuple :: Proxy a  - >也许(ProxyTupleEx a)

让它有机会失败。



现在我们来到您的关于反思的其他问题。我们需要添加一个 Typeable 约束,以便我们可以反映该类型,但是一旦习惯了库的节奏,它就相当简单:

  proxyTuple :: Typeable a =>代理a  - >也许(ProxyTupleEx a)
proxyTuple p
| App_proxy(App(应用程序元组a)b)< -typeOf p
,Just HRefl< -eqTypeRep元组(typeRep :: TypeRep(,))
= Just(ProxyTupleEx p)
|否则
= Nothing

现在,如果您在 ProxyTupleEx一个,编译器会知道 a 实际上是一个元组。

  tupleLength ::(a,b) - > Int 
tupleLength _ = 2

示例:: Typeable a =>代理a - > a - > Int
示例代理x
| Just(ProxyTupleEx_)< - proxyTuple proxy = tupleLength x
- x现在已知是元组
- 所以这个类型检测
|否则= 0

像魔术一样,这个类型检查和工作:

  ghci>例如代理(1,2)
2
ghci>示例代理0
0

(也是代理在这里是不必要的,因为我们已经有了 a 类型,但为了与查询保持一致,我将它包含在内)。

Let's say I have a standard proxy with some type a hidden inside:

pxyA = Proxy :: Proxy a

Because of other parts of my program, I know for a fact that a is actually a tuple of two other types, say (b,c). Is there any way for me to extract that information from my original proxy with a function like:

f :: Proxy a -> (Proxy b, Proxy c)

or

f :: Proxy a -> Proxy (b,c)

The main thing stopping me is that I don't know what the types b or c are going to be, just that I need to pass them to other parts of my program.

I've already written a trivial function with a similar form:

splitPxyTup :: forall a b . Proxy (a,b) -> (Proxy a, Proxy b)
splitPxyTup _ = (Proxy :: Proxy a, Proxy :: Proxy b)

but keep getting lost on how to convince the type system that my original proxy actually is a tuple type.

I also thought about using a cast, but since I don't know what the output types are, I won't be able to get anything meaningful from it.

解决方案

I've been trying to see what you're after and can't quite, it would be helpful if you could produce a more complete example that represents your problem.

Until then, I seem to have an answer for this part of your question

The main thing stopping me is that I don't know what the types b or c are going to be...

From that sentence it sounds like you need an existential:

proxyTuple :: Proxy a -> exists b c. Proxy (b,c)

which is not valid Haskell, but we can encode it easily:

data ProxyTupleEx where
    ProxyTupleEx :: Proxy (b,c) -> ProxyTupleEx

It's not quite enough though, because we could easily implement this function in a trivial way.

proxyTuple :: Proxy a -> ProxyTupleEx
proxyTuple _ = ProxyTupleEx (Proxy :: Proxy ((), ()))

We need to also specify the connection with the incoming a. This we can do:

data ProxyTupleEx a where
    ProxyTupleEx :: (a ~ (b,c)) => Proxy (b,c) -> ProxyTupleEx a

We won't be able to implement proxyTuple now, because it has no implementation when a is not a tuple. We need

proxyTuple :: Proxy a -> Maybe (ProxyTupleEx a)

giving it the opportunity to fail.

Now we get to your other question about reflection. We need to add a Typeable constraint so that we can reflect about the type, but then it is fairly straightforward once you are used to the cadence of the library:

proxyTuple :: Typeable a => Proxy a -> Maybe (ProxyTupleEx a)
proxyTuple p
    | App _proxy (App (App tuple a) b) <- typeOf p
    , Just HRefl <- eqTypeRep tuple (typeRep :: TypeRep (,))
    = Just (ProxyTupleEx p)
    | otherwise
    = Nothing

Now if you pattern match on a ProxyTupleEx a, the compiler will know that a is actually a tuple.

tupleLength :: (a,b) -> Int
tupleLength _ = 2

example :: Typeable a => Proxy a -> a -> Int
example proxy x
    | Just (ProxyTupleEx _) <- proxyTuple proxy = tupleLength x
                                                  -- x is now known to be a tuple
                                                  -- so this typechecks
    | otherwise = 0

Like magic, this typechecks, and works:

ghci> example Proxy (1,2)
2
ghci> example Proxy 0
0

(Also the Proxy here is unnecessary since we already have the type of a, but I included it for consistency with the query.)

这篇关于你如何从代理中提取类型信息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆