2012-06-04 9 views
19

Dynamicの値に多相関数を適用するには正当な方法はありますか?多項式関数を動的値に適用する方法

たとえば、タイプがDynamicで、の値にJustを適用したいとします。だから値がtoDyn Trueによって構築された場合、結果はtoDyn (Just True)になります。 Dynamicの内部で発生する可能性があるさまざまな種類の数は制限されていません。

(関与型が閉じられた宇宙から来たとき、私は解決策を持っていますが、それは不快だ。)

+0

これは、 'polytypeable'と' polytypeable-utils'のように見えますが、最悪の場合でも完全な統一を実装する必要があります。 – Carl

答えて

15

これはおそらく、sanestアプローチではないですが、私たちはTYPEREP偽るために私のreflectionパッケージを乱用することができます。

{-# 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ていない場合でも、それらを避けるために管理します。あなたが内部でTypeRepで行う必要がある何を、あなた自身のDynamic'データ型に

data Dynamic = Dynamic TypeRep Any 

unsafeCoerce、そしてあなたの関数を適用した後:

別のパスがちょうどDynamicの実装を利用することであろう、unsafeCoerceすべてを返します。

+2

'TypeRep'に嘘をついているのは独創的なので、私はこの答えを受け入れるでしょう(' unsafeCoerce'を使って 'Dynamic'の中で覗くと撫でるのは普通ではありません)。 – augustss

+0

@augustss:道徳的な違いはどこですか? –

+1

@AndreasRossbergとても小さいです。 :)しかし、前者はやや頑強です。たとえば、 'Dynamic'の実装が変更され、' TypeRep'フィールドと 'Any'フィールドが変更された場合、前者は動作し、後者はクラッシュします。 – augustss

関連する問題