2011-12-16 9 views
6

Ho una caldaia abbastanza comune di Haskell che si presenta in molti posti. E 'simile a questa (quando Istanziare classi):Rimozione della piastra di collegamento comune delle pipe Haskell

a <= b = (modify a) <= (modify b) 

come questo (con le funzioni normali):

fn x y z = fn (foo x) (foo y) (foo z) 

e talvolta anche con tuple, come in:

mod (x, y) = (alt x, alt y) 

E' sembra che ci dovrebbe essere un modo semplice per ridurre tutto questo boilerplate e non dover ripetere me stesso così tanto. (Questi sono semplici esempi, ma è fastidioso). Immagino che ci siano delle astrazioni create per rimuovere una simile piastra, ma non sono sicuro di come si chiamino né dove cercare. Qualche haskellite può indicarmi la giusta direzione?

risposta

12

Per il caso (<=), prendere in considerazione la definizione compare invece; è quindi possibile utilizzare Data.Ord.comparing, in questo modo:

instance Ord Foo where 
    compare = comparing modify 

Nota che comparing può essere semplicemente definito come comparing f = compare `on` f, utilizzando Data.Function.on.

Per l'esempio fn, non è chiaro. Non c'è modo di semplificare questo tipo di definizione in generale. Tuttavia, non credo che il boilerplate sia troppo brutto in questo caso.

Per mod:

mod = alt *** alt 

usando Control.Arrow.(***) - leggere a b c come b -> c nella firma tipo; le frecce sono solo un'astrazione generale (come i funtori o le monadi) di cui le funzioni sono un'istanza. Potresti definire both = join (***) (che è esso stesso abbreviazione di both f = f *** f); Conosco almeno un'altra persona che usa questo alias e penso che dovrebbe essere in Control.Arrow appropriato.

Quindi, in generale, la risposta è: combinatori, combinatori, combinatori! Questo si collega direttamente allo stile point-free. Può essere esagerato, ma quando i combinatori esistono per la tua situazione, tale codice può non solo essere più pulito e più breve, può essere più facile da leggere: devi solo imparare un'astrazione una volta, e poi applicarlo ovunque durante la lettura del codice.

Suggerisco di utilizzare Hoogle per trovare questi combinatori; quando pensi di vedere uno schema generale alla base di una definizione, prova ad astrarre ciò che pensi siano le parti comuni, prendendo il tipo di risultato e cercandolo su Hoogle. Potresti trovare un combinatore che fa esattamente ciò che vuoi.

Così, per esempio, per la vostra mod caso, si potrebbe astrarre alt, cedendo \f (a,b) -> (f a, f b), quindi cercare il suo tipo, (a -> b) -> (a, a) -> (b, b) - c'è una corrispondenza esatta, ma è nella biblioteca grafo FGL, che non si vuole dipendere da. Ancora, puoi vedere come la capacità di cercare per tipo può essere davvero molto preziosa!

C'è anche una versione da riga di comando di Hoogle con integrazione GHCi; vedere il suo HaskellWiki page per ulteriori informazioni.

(C'è anche Hayoo, che cerca la totalità della Hackage, ma è un po 'meno intelligente con tipi;., Che quella che si usa è fino a preferenze personali)

4

Per alcuni dei boilerplate, Data.Function.on può essere utile, anche se in questi esempi, non guadagnare molto

instance Ord Foo where 
    (<=) = (<=) `on` modify -- maybe 

mod = uncurry ((,) `on` alt) -- Not really 
Problemi correlati