2013-01-16 12 views
8

continuo riutilizzo espressioni lambda comePointfree (o libreria) per applicare due funzioni a singolo ingresso

\x -> (f x, g x) 

dove applico lo stesso ingresso a due funzioni e incapsulare il risultato in una coppia. Posso scrivere una funzione catturare questa

combine :: (a -> b) -> (a -> c) -> a -> (b,c) 
combine f g x = (f x, g x) 

Ora l'espressione lambda sopra è solo combine f g. Ho due domande.

  1. Sono interessato a sapere se esiste una funzione di libreria standard che esegue ciò che non riesco a trovare.
  2. Per curiosità, vorrei riscrivere questa funzione in stile point-free, ma ho un sacco di problemi.

risposta

12
  1. Control.Arrow ha la funzione (&&&) per questo. Ha un tipo "più generale", che purtroppo significa che Hoogle non lo trova (forse questo dovrebbe essere considerato un bug in Hoogle?).

  2. Di solito è possibile calcolare questo genere di cose automaticamente pointfree, che lambdabot in #haskell ha come plugin.

Ad esempio:

<shachaf> @pl combine f g x = (f x, g x) 
<lambdabot> combine = liftM2 (,) 

Dove liftM2 con la (r ->) istanza di Monad ha tipo (a -> b -> c) -> (r -> a) -> (r -> b) -> r -> c. Certamente, ci sono molti altri modi per scrivere questo senza punti, a seconda di quali primitive permetti.

+0

Grazie per la risposta concisa, e grazie per la segnalazione a me pointfree. – bshourd

12

Sono interessato a sapere se esiste una funzione di libreria standard che esegue ciò che non riesco a trovare.

È facile mancare a causa della classe di tipo, ma look at Control.Arrow. I normali Arrow s non possono essere ritentati o applicati, quindi i combinatori Arrow sono esenti da punti per necessità. Se li siete specializzati a (->), troverete quello che si desidera è questo:

(&&&) :: (Arrow a) => a b c -> a b c' -> a b (c, c') 

Ci sono altre, funzioni simili, come ad esempio l'operazione equivalente per Either, che si è specializzata a (->) assomiglia a questo:

(|||) :: (a -> c) -> (b -> c) -> Either a b -> c 

Che è uguale a either.

Per curiosità, mi piacerebbe riscrivere questa funzione in stile point-free, ma sto avendo un sacco di problemi con esso.

Dal momento che si sta duplicando un ingresso, è necessario un modo di fare che pointfree - il modo più comune è tramite l'istanza Applicative o Monad per (->), per esempio \f g ->(,) < $ > f < *> g . Questo è essenzialmente un monad implicito, in linea Reader, e l'argomento che viene diviso è il valore "ambiente". Usando questo approccio, join f x diventa f x x, pure o return diventano const, fmap diventa (.), e (<*>) diventa il S combinator\f g x -> f x (g x).

+2

Parte del motivo per cui le funzioni Control.Arrow sono difficili da perdere è che Hoogle non unificherà le variabili di tipo con '->', anche se i tipi corrispondono, quindi [Hoogling per '(a -> b) -> (a -> c) -> a -> (b, c) '] (http://www.haskell.org/hoogle/?q= (a + -% 3E + b) + -% 3E + (a + -% 3E + c) + -% 3E + a + -% 3E + (b% 2Cc)) non riesce a trovare '(&&&)'. ([Hoogling per 'fab -> fac -> fa (b, c)'] (http://www.haskell.org/hoogle/?q=f+a+b+-%3E+f+a+c+- % 3E + f + a + (b% 2Cc) funziona, così come (con un avvertimento) [Hoogling per '(a ~> b) -> (a ~> c) -> (a ~> (b, c)) '] (http://www.haskell.org/hoogle/?hoogle=%28a+~%3E+b%29+-%3E+%28a+~%3E+c%29+-%3E+a+~%3E+% 28b% 2Cc% 29)). –

+1

Grazie a entrambi per questo, questo è esattamente ciò che volevo sapere. Grazie Antal per aver evidenziato la sintassi 'a ~> b' per Hoogle, di cui non sapevo. – bshourd

6

Ci sono in realtà diversi modi per farlo. Il modo più comune è quello di utilizzare la funzione di (&&&) da Control.Arrow:

f &&& g 

Tuttavia, spesso si hanno più funzioni o necessità di passare il risultato a un'altra funzione, nel qual caso è molto più comodo da usare stile applicativa. Poi

uncurry (+) . (f &&& g) 

diventa

liftA2 (+) f g 

Come ha fatto notare questo può essere utilizzato con più di una funzione:

liftA3 zip3 f g h 
+0

Grazie , in particolare per la spiegazione "uso con più di una funzione" – bshourd

+1

E questi possono ovviamente essere riscritti con '<$>' e '<*>': 'zip3 <$> f <*> g <*> h'. A volte questo è più chiaro dell'uso di' liftA * '. –

Problemi correlati