【问题标题】:How to apply a polymorphic function to a Dynamic value如何将多态函数应用于动态值
【发布时间】:2012-06-09 00:29:46
【问题描述】:

有没有一种理智的方法可以将多态函数应用于Dynamic 类型的值?

例如,我有一个Dynamic 类型的值,我想将Just 应用于Dynamic 中的值。所以如果值是由toDyn True 构造的,我希望结果是toDyn (Just True)Dynamic 中可以出现的不同类型的数量没有限制。

(当涉及的类型来自一个封闭的宇宙时,我有一个解决方案,但这很不愉快。)

【问题讨论】:

  • 看起来 polytypeablepolytypeable-utils 可以用于此 - 尽管在最坏的情况下您仍然必须实现完全统一。

标签: haskell types dynamic-typing


【解决方案1】:

这可能不是最明智的方法,但我们可以滥用我的 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 撒谎很巧妙,所以我会接受这个答案(使用unsafeCoerceDynamic 内部偷看和戳不符合理智)。
  • @augustss:道德差异在哪里?
  • @AndreasRossberg 它非常小。 :) 但前者更健壮一些。例如,如果 Dynamic 的实现发生变化,TypeRepAny 字段发生变化,前者仍然有效,而后者崩溃。
  • 现在你不能编写自定义 Typeable 实例,这将不再有效,对吧?
  • 使用 GHC 8.0 将会有一个新的“正确的”TypeRep,它实际上将包含类型中的“a”。这将使许多此类黑客行为变得更容易、更安全。
猜你喜欢
  • 2019-07-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多