有没有一种理智的方法可以将多态函数应用于 type 的值Dynamic
?
例如,我有一个类型的值,我Dynamic
想将其应用于. 因此,如果该值是由我构建的,我希望结果是. 内部可以出现的不同类型的数量是没有限制的。Just
Dynamic
toDyn True
toDyn (Just True)
Dynamic
(当涉及的类型来自封闭的宇宙时,我有一个解决方案,但这很不愉快。)
有没有一种理智的方法可以将多态函数应用于 type 的值Dynamic
?
例如,我有一个类型的值,我Dynamic
想将其应用于. 因此,如果该值是由我构建的,我希望结果是. 内部可以出现的不同类型的数量是没有限制的。Just
Dynamic
toDyn True
toDyn (Just True)
Dynamic
(当涉及的类型来自封闭的宇宙时,我有一个解决方案,但这很不愉快。)
这可能不是最明智的方法,但我们可以滥用我的reflection
包来对 TypeRep 撒谎。
{-# LANGUAGE Rank2Types, FlexibleContexts, ScopedTypeVariables #-}
import Data.Dynamic
import Data.Proxy
import Data.Reflection
import GHC.Prim (Any)
import Unsafe.Coerce
newtype WithRep s a = WithRep { withRep :: a }
instance Reifies s TypeRep => Typeable (WithRep s a) where
typeOf s = reflect (Proxy :: Proxy s)
鉴于我们现在可以查看TypeRep
我们的Dynamic
参数并适当地实例化我们的Dynamic
函数。
apD :: forall f. Typeable1 f => (forall a. a -> f a) -> Dynamic -> Dynamic
apD f a = dynApp df a
where t = dynTypeRep a
df = reify (mkFunTy t (typeOf1 (undefined :: f ()) `mkAppTy` t)) $
\(_ :: Proxy s) -> toDyn (WithRep f :: WithRep s (() -> f ()))
如果base
只是apD
为我们提供类似的东西可能会容易得多,但这需要 2 级类型,并且Typeable
/Dynamic
设法避免它们,即使Data
没有。
另一种方法是仅利用以下实现Dynamic
:
data Dynamic = Dynamic TypeRep Any
unsafeCoerce
对于你自己的数据类型,在内部Dynamic'
做你需要做的事情,TypeRep
在应用你的函数之后,unsafeCoerce
一切都回来了。