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

问题描述

限时删除!!

假设我有一个标准的。我们需要添加一个 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

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.)

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

1403页,肝出来的..

09-07 02:06