有没有一种合理的方法将多态函数应用于类型为 Dynamic
的值?
例如,我有一个类型为 Dynamic
的值,并且我想将 Just
应用于 Dynamic
内部的值。因此,如果该值是通过 toDyn True
构造的,则希望结果为 toDyn (Just True)
。可以出现在 Dynamic
内部的不同类型数量没有限制。
(当涉及的类型来自封闭宇宙时,我有一个解决方案,但它很不愉快。)
有没有一种合理的方法将多态函数应用于类型为 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)
考虑到我们现在可以查看Dynamic
参数的TypeRep
并适当实例化我们的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
将所有内容转换回去。
TypeRep
的欺骗是巧妙的,所以我会接受这个答案(使用 unsafeCoerce
来窥视和操作 Dynamic
不被视为明智的做法)。 - augustssDynamic
的实现发生变化,使得TypeRep
和Any
字段交换位置,前者仍然可以工作,而后者会崩溃。 - augustssTypeable
实例,所以这不再起作用了,对吧? - GS - Apologise to Monica
polytypeable
和polytypeable-utils
可以用于此 - 尽管在最坏的情况下仍需要实现完整的统一。 - Carl