ジェネリックプログラミングの時間!
関数がある場合:
f :: a1 -> a2 -> a3 -> ... -> an
と値
v :: aX -- where 1 <= x < n
コンパイル時にf
、値のどの引数がv
(もしあれば)正しいタイプであるかを知らなくても、部分的に適用できますf
かv
?(Typeable、Data、TH、またはその他のトリックを使用)
もう少ししっかりと、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
具体的には)を使用することv
がの3番目の引数であることは知っていますがf
、それは部分的に適用する方法があるという意味ではありません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