问题描述
假设我有一个标准的。我们需要添加一个 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.)
这篇关于你如何从代理中提取类型信息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!