¡Tiempo de programación genérico!Uso de Typeable para aplicar parcialmente en tiempo de ejecución (cualquier tipo de hora coincide)
Si tengo una función:
f :: a1 -> a2 -> a3 -> ... -> an
y un valor
v :: aX -- where 1 <= x < n
Sin saber en tiempo de compilación cuál de los argumentos de f
el valor v
es el tipo correcto para (si los hay) ¿Puedo aplicar parcialmente f
a v
? (usando Typeable, Data, TH o cualquier otro truco)
Un poco más sólidamente, ¿puedo construir la función g
(abajo) en tiempo de ejecución? ¡En realidad no tiene que ser polimórfico, todos mis tipos serán monomórficos!
g :: (a1 -> a2 -> a3 -> a4 -> a5) -> a3 -> (a1 -> a2 -> a4 -> a5)
g f v = \x y z -> f x y v z
sé que, utilizando tipable (typeRepArgs
específicamente), v
es la tercera argumento de f
, pero eso no quiere decir que tenga una forma de aplicar parcialmente f
.
Mi código, probablemente se vería como:
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
¿Hay algo que se puede poner en práctica el magicApplyFunction
?
EDIT: finalmente volví a jugar con esto. La función mágica aplicar es:
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
No hay nada de malo en ** g **, por lo que puedo ver, y el polimorfismo tampoco importa. Del mismo modo que puedes usar el flip cada vez que tienes una función y el segundo argumento, ya sabes. – Ingo
¡Pero no tengo 'g' en tiempo de compilación! ¿Cómo puedo generarlo en tiempo de ejecución? IIRC, no puedo pasar funciones hacia adelante y hacia atrás a/from hint –
Escribir la función para aplicarla a través de th no debería ser un problema - el problema es qué tipo de valor recuperas (Dynamic/Box) es, como te das cuenta, tu única opción. – sclv