如何将多态函数应用于动态值

aug*_*tss 19 haskell types dynamic-typing

是否有一种理智的方法将多态函数应用于类型的值Dynamic

例如,我有一个类型的值,Dynamic我想应用于Just内部的值Dynamic.因此,如果值是由toDyn True我希望结果构建的toDyn (Just True).内部可能出现的不同类型的数量Dynamic不受限制.

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

Edw*_*ETT 15

这可能不是最认真的方法,但我们可以滥用我的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)
Run Code Online (Sandbox Code Playgroud)

鉴于我们现在可以查看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 ()))
Run Code Online (Sandbox Code Playgroud)

如果baseapD为我们提供类似的东西可能会容易得多,但这需要排名2类型,并且Typeable/ Dynamic设法避免它们,即使Data没有.

另一条路径就是利用以下方面的实施Dynamic:

data Dynamic = Dynamic TypeRep Any
Run Code Online (Sandbox Code Playgroud)

unsafeCoerce根据您自己的Dynamic'数据类型,TypeRep在内部执行您需要执行的操作,并在应用您的函数后,unsafeCoerce返回所有内容.

  • 说谎'TypeRep`是巧妙的,所以我会接受这个答案(使用`unsafeCoerce`偷看并戳"动态"不符合理智). (2认同)
  • 使用GHC 8.0,将会有一个新的"正确"TypeRep,它实际上将包含类型中的"a".这将使很多这样的黑客攻击变得更容易和更安全. (2认同)