2015-09-30 15 views
14

stavo giocando intorno con una semplice funzione per qualcun altro di domanda Stack Overflow, e ho scritto l'espressione (con applicativo ((>) t), forse?):Rimozione di duplicazione -

f a x ++ f a y 

Ovviamente questo è il il modo migliore per scrivere quell'espressione nella vita reale, dato che ho tutte quelle variabili in ogni caso, ma ho visto la duplicazione di f a e ho pensato "Ehi, forse puoi rimuoverlo con l'istanza Applicativa per le funzioni". Ho finito con:

liftA2 (++) (flip f x) (flip f y) a 

che è semplicemente orribile. C'è un modo più carino per rimuovere questa duplicazione? Ovviamente potrei anche rimuovere la duplicazione legando f a a qualcosa in una clausola where, ma questo era inteso come un esercizio nell'uso di funzioni built-in.

risposta

21

Si potrebbe fare

((++) `on` f a) x y 

che non utilizza Applicative, anche se (mi dispiace).

+0

Mi piace questa risposta, anche se! Immagino che non stavo veramente cercando le risposte Applicative in modo specifico, tanto quanto usare la libreria standard per rimuovere la duplicazione. – amalloy

21

[...] forse è possibile rimuoverlo con l'istanza Applicativa per le funzioni.

È necessario utilizzare l'istanza Applicative di ((->) t)? Se vuoi semplicemente sbarazzarti del duplicato f a, perché non usare la lista monad, invece?

[x, y] >>= f a 

o, equivalentemente,

f a =<< [x, y] 

Esempio:

λ> let f :: Int -> Int -> [Int]; f a x = [a .. x] 

λ> f 1 2 ++ f 1 3 
[1,2,1,2,3] 

λ> [2, 3] >>= f 1 
[1,2,1,2,3] 

λ> f 1 =<< [2, 3] 
[1,2,1,2,3] 
+0

Vale la pena notare che '= <<' è uguale a 'concatMap' in questa situazione, quindi se si vuole pensare a questo in termini di manipolazioni di liste invece di monadi, questa è la funzione da usare. –

+0

@ cool_me5000 Certo, ma volevo sottolineare l'aspetto monadico dell'operazione. – Jubobs

14

Bikeshedding è divertente! Un'altra opzione sarebbe quella di utilizzare l'istanza Monoid per le funzioni:

(($x) <> ($y)) (f a) 
+1

Non capisco questo. La composizione non è 'mappend', per le funzioni? E cosa è successo al '++'? – amalloy

+0

@amalloy Per le funzioni, 'mappend' è l'aggiunta puntuale:' mappend f g x = mappend (f x) (g x) '. Il '(++)' scompare perché è il 'mappend' che accade in ogni punto. –

3

Poiché la questione ha accennato a una soluzione che utilizza applicativo (anche se altre risposte sono più elegante) ...

((++) <$> ($ x) <*> ($ y)) (f a) 
+0

Se si desidera eliminare alcune parentesi, è possibile scrivere: '(++) <$> ($ x) <*> ($ y) $ f a'. – Jubobs

+1

@Jubobs Non sono sicuro che abbia ragione o no, ma ho deciso di testare su strada il consiglio di Gabriel Gonzalez di rendere il codice Haskell più leggibile ai non-Haskellers: http://www.haskellforall.com/2015/09 /how-to-make-your-haskell-code-more.html. Evitare '($)' è la sua migliore raccomandazione. – frasertweedale

+0

Grazie per il collegamento ':)' – Jubobs

Problemi correlati