forma libre de puntos versus estilo
-
26-09-2019 - |
Pregunta
¿Se puede convertir
-- tupleUnfold :: forall a. ((forall b. a -> b)) -> a -> ((b))
tupleUnfold :: Int -> ExpQ
tupleUnfold n = do
xs <- forM [1 .. n] (const . newName $ "x")
y <- newName "y"
let y' = varE y
g (ps', es') x = (varP x : ps', appE (varE x) y' : es')
(ps, es) = foldl' g ([], []) xs
lamE [tupP ps, varP y] (tupE es)
para pointfree estilo, manteniendo la claridad (sé de la 'pointfree' programa, pero preferiría no ofuscar el código aún más)?
De cualquier manera, ¿qué cambios se podrían hacer para mejorar el estilo de la función, o de otra manera hace su clara intención? La función está destinado a ser utilizado como a continuación.
$(tupleUnfold 3) ((+ 1), (+ 2), (+ 3)) 2
-- (3, 4, 5)
¿Cuáles son algunas de las convenciones de nombres para un mejor uso (ver el PS, PS', ES, y es' variables)?
Solución
Esto es lo que tengo. Control.Arrow (&&&)
necesidades y Control.Applicative (<$>)
.
tupleUnfold :: Int -> ExpQ
tupleUnfold n = do
y <- newName "y"
(ps,es) <- unzip . map (varP &&& (`appE` varE y) . varE)
<$> replicateM n (newName "x")
lamE [tupP ps, varP y] (tupE es)
No se pudo sacar ventaja en ello mucho más sin que sea totalmente incomprensible.
Editar Si bien no es punto libre, aquí está el más clara que podría hacerlo. Necesidades Data.Function (on)
tupleUnfold :: Int -> ExpQ
tupleUnfold n = do
y <- newName "y"
xs <- replicateM n (newName "x")
let exps = tupE $ zipWith appVars xs (repeat y)
pats = tupP $ map varP xs
lamE [pats, varP y] exps
where
appVars = appE `on` varE
Otros consejos
un poco más incomprensible (tratar de leer de derecha a izquierda):
tupleUnfold n = do
y <- newName "y"
uncurry lamE . ((:[varP y]) . tupP *** tupE) . unzip .
map (varP &&& (`appE` varE y) . varE) <$> replicateM n (newName "x")
Editar :
Mezcla de flechas y la composición de funciones para procesar
tupleUnfold n = do
y <- newName "y"
uncurry lamE . ((tupP >>> (:[varP y])) *** tupE) . unzip .
map (varP &&& (varE >>> (`appE` varE y))) <$> replicateM n (newName "x")
y utilizando la mayoría de las flechas (leer función de procesamiento de izquierda a derecha)
tupleUnfold n = do
y <- newName "y"
(map (varP &&& (varE >>> (`appE` varE y))) >>> unzip >>>
((tupP >>> (:[varP y])) *** tupE) >>> uncurry lamE) <$> replicateM n (newName "x")
nota que la función de flecha (>>>) es equivalente a flip (.)
En lo personal creo que está bastante claro ya, pero ¿qué tal esto:
tupleUnfold :: Int -> ExpQ
tupleUnfold = mapM (const . newName $ "x") . enumFromTo 1 >=> \xs -> do
y <- newName "y"
let y' = varE y
g (ps', es') x = (varP x : ps', appE (varE x) y' : es')
f ps = lamE [tupP ps, varP y] . tupE
uncurry f $ foldl' g ([],[]) xs
El >=>
Kleisli operador composición (de Control.Monad) es útil para crear pointfree funciones monádicos.