2011-04-21 8 views
6

ジェネリックプログラミング時間!実行時に型付き関数を部分的に適用する(任意の時間型が一致する)

私が機能している場合:

f :: a1 -> a2 -> a3 -> ... -> an 

と値vがための右のタイプがあるfの引数のコンパイル時に知らず値

v :: aX -- where 1 <= x < n 

を(もしあれば) 、部分的にfvに適用できますか?

実行時に関数g(下)を少し強固に構築できますか?それは実際に多形である必要はありません、私のすべての型は単形です!

g :: (a1 -> a2 -> a3 -> a4 -> a5) -> a3 -> (a1 -> a2 -> a4 -> a5) 
g f v = \x y z -> f x y v z 

私はTypeable(特にtypeRepArgs)、vfの第三引数であるが、それは私が部分的にfを適用する方法が意味するものではありませんを使用して、ことを知っています。

私のコードは、おそらく次のようになります。

import Data.Typeable 

data Box = forall a. Box (TyRep, a) 

mkBox :: Typeable a => a -> Box 
mkBox = (typeOf a, a) 

g :: Box -> Box -> [Box] 
g (Box (ft,f)) (Box (vt,v)) = 
    let argNums = [n | n <- [1..nrArgs], isNthArg n vt ft] 
    in map (mkBox . magicApplyFunction f v) argNums 

isNthArg :: Int -> TyRep -> TyRep -> Bool 
isNthArg n arg func = Just arg == lookup n (zip [1..] (typeRepArgs func)) 

nrArgs :: TyRep -> Int 
nrArgs = (\x -> x - 1) . length . typeRepArgs 

magicApplyFunctionを実装できることはありますか?

編集:私はついにこれを再生しました。私は今のところ、ここで全体のソリューションを書くつもりはない

buildFunc :: f -> x -> Int -> g 
buildFunc f x 0 = unsafeCoerce f x 
buildFunc f x i = 
     let !res = \y -> (buildFunc (unsafeCoerce f y) x (i-1)) 
     in unsafeCoerce res 
+0

私が見る限り、** g **には何も問題はなく、多型も問題ではありません。関数と2番目の引数を持つたびにフリップを使うことができるのと同じように、あなたは知っています。 – Ingo

+0

コンパイル時には 'g'がありません!実行時にどのように生成できますか? IIRC、私はヒントと前後に関数を渡すことができません –

+0

th経由で適用する関数を書くことは問題ではありません。問題は戻り値(Dynamic/Box)はあなたは、あなたの唯一の選択肢を実現します。 – sclv

答えて

2

、私はこれはData.DynamicTypeableで純粋に行うことができると確信している:魔法適用関数です。 dynApplyfunResultTyのソースは重要な要素を提供する必要があります:

dynApply :: Dynamic -> Dynamic -> Maybe Dynamic 
dynApply (Dynamic t1 f) (Dynamic t2 x) = 
    case funResultTy t1 t2 of 
    Just t3 -> Just (Dynamic t3 ((unsafeCoerce f) x)) 
    Nothing -> Nothing 


funResultTy :: TypeRep -> TypeRep -> Maybe TypeRep 
funResultTy trFun trArg 
    = case splitTyConApp trFun of 
     (tc, [t1,t2]) | tc == funTc && t1 == trArg -> Just t2 
     _ -> Nothing 

物事をシンプルに保つために、私はtype Box = (Dynamic, [Either TypeRep Dynamic])を持っていると思います。後者は、引数のtyperepsのリストとして始まります。 magicApplyは、ボックス内で最初に一致するTypeRepを探し、値のDynamicを代入します。次にBoxにすべての引数がmagicappliedされているextractを持つことができます。実際にはdynApply呼び出しを実行して結果の動的結果を生成します。

+0

これは、 'x'が' f'の最初の引数の正しい型であることを動的にチェックしていませんか?(フリップ/引数の並べ替えなし)? 'f :: Int - > Double-> Bool'と' x :: Double'の場合、 'f'と' x'を組み合わせて 'h :: Int - > Bool'を取得します。私はあなたの答えのポイントを逃したのですか? –

+0

@TomMDこれはdynApplyとfunResultTyの機能です。それらはライブラリ定義からのコピー/ペーストだけです。 *どのように彼らがそれを行うのかは、関数の引数の完全なリストを抽出する方法を示します。関数の引数リストは、そのコードの下でスケッチしたソリューションを実装するために使用できます。 – sclv

+0

ああ、私はあなたのポイントを参照してください。これでちょっと感謝します! –

1

hm ..のみ入力できますか?良い古いOverlappingInstancesはどうですか?

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

class Magical a b c where 
    apply :: a -> b -> c 

instance (AreEqual a c e, Magical' e (a -> b) c r) => Magical (a -> b) c r where 
    apply f a = apply' (undefined :: e) f a 


class Magical' e a b c where 
    apply' :: e -> a -> b -> c 

instance (r ~ b) => Magical' True (a -> b) a r where 
    apply' _ f a = f a 

instance (Magical b c d, r ~ (a -> d)) => Magical' False (a -> b) c r where 
    apply' _ f c = \a -> apply (f a) c 


data True 
data False 

class AreEqual a b r 
instance (r ~ True) => AreEqual a a r 
instance (r ~ False) => AreEqual a b r 


test :: Int -> Char -> Bool 
test i c = True 

t1 = apply test (5::Int) 
t2 = apply test 'c' 
関連する問題