Ponto-de forma livre versus estilo
-
26-09-2019 - |
Pergunta
Você pode converter
-- 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, mantendo a claridade (eu sei do programa "pointfree', mas prefere não ofuscar o código ainda mais)?
De qualquer forma, que mudanças poderiam ser feitas para melhorar o estilo da função, ou caso contrário, faz a sua intenção mais clara?A função destina-se a ser usado como abaixo.
$(tupleUnfold 3) ((+ 1), (+ 2), (+ 3)) 2
-- (3, 4, 5)
Quais são algumas das melhores convenções de nomenclatura para uso (consulte o ps, ps', es, es, as variáveis)?
Solução
Aqui está o que eu tenho.Necessidades Control.Arrow (&&&)
e 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)
Não podia acabar com ele muito mais sem torná-lo totalmente incompreensível.
EDITAR Enquanto não do ponto de graça, aqui é o clara Eu poderia fazer isso.Necessidades 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
Outras dicas
um pouco mais incompreensível (tente ler da direita para a esquerda):
tupleUnfold n = do
y <- newName "y"
uncurry lamE . ((:[varP y]) . tupP *** tupE) . unzip .
map (varP &&& (`appE` varE y) . varE) <$> replicateM n (newName "x")
EDITAR:
mistura de setas e a função de composição para o processamento
tupleUnfold n = do
y <- newName "y"
uncurry lamE . ((tupP >>> (:[varP y])) *** tupE) . unzip .
map (varP &&& (varE >>> (`appE` varE y))) <$> replicateM n (newName "x")
e utilizando principalmente setas (leia-se função de processamento de da esquerda para a direita)
tupleUnfold n = do
y <- newName "y"
(map (varP &&& (varE >>> (`appE` varE y))) >>> unzip >>>
((tupP >>> (:[varP y])) *** tupE) >>> uncurry lamE) <$> replicateM n (newName "x")
observe que a seta função (>>>) é equivalente a flip (.)
Pessoalmente, eu acho que é bastante claro que já, mas quanto a isso:
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
O Kleisli composição do operador >=>
(a partir de Controlo.Mônada) é útil para a criação de pointfree monádico funções.