2016-01-10 7 views
8

reflectionパッケージは反射リスクの不整合はありますか?

reify :: a -> (forall s . Reifies s a => Proxy s -> r) -> r 

が与えられたクラス

class Reifies s a | s -> a where 
    reflect :: proxy s -> a 

と機能を提供する唯一のこれらの、1でしむしろひどく、例えば、インスタンス

instance Reifies s Int where 
    reflect _ = 0 
を与えることによって台無しに

、なぜなら例えば、

これは悪いだろう
reify (1 :: Int) $ \p -> reflect p 

は合法(reifyを適用する前に渡された関数を特化することにより)(通常の反射プロセスを介して)1又は0のいずれかを生成することができます。

Data.Reflectionには、実際には、このような悪用がブロックされているように見えます。Reifies私が記述した悪のインスタンスは、重複として拒否されます。オーバーラップするインスタンスが有効になっている場合は、私は専門の重複がもたらす不確実性によってブロックされることがあります信じています。おそらくGADTsのヘルプまたは一部などで、日陰のインスタンスでこれを公開するいくつかの方法があるかどう

それでも、私は思ったんだけど。

答えて

4

私は暫定的にそれは矛盾を危険にさらすしないと言います。いくつかの工夫の後、私はreflectをハイジャックすることを考え出すことができ最良の方法は、矛盾を得るのに当然十分である、INCOHERENTを使用:

{-# LANGUAGE 
    TypeFamilies, FlexibleInstances, MultiParamTypeClasses, 
    ScopedTypeVariables #-} 

import Data.Constraint 
import Data.Proxy 
import Data.Reflection 

instance {-# INCOHERENT #-} Reifies (s :: *) Int where 
    reflect _ = 0 

reflectThis :: forall (s :: *). Dict (Reifies s Int) 
reflectThis = Dict 

-- prints 0 
main = print $ 
    reify (1 :: Int) $ \(p :: Proxy s) -> 
    case reflectThis :: Dict (Reifies s Int) of 
    Dict -> reflect p 
+0

GHCが上 'SPECIALIZE'を使用することによってだまさすることができれば、うーん...私は疑問に思います関数は最終的に 'reify'に渡されました。私は家に帰るときにそれを試みるつもりです。 – dfeuer

+0

@dfeuerは、あなたはそれを試してみましたか? –