2013-01-16 2 views
8

I halten Lambda-Ausdrücke Wiederverwendung wiePointfree (oder Bibliothek) Funktion zum Anlegen von zwei Funktionen einzelnen Eingang

\x -> (f x, g x) 

wo I die gleiche Eingabe an zwei Funktionen übernehmen und das Ergebnis in einem Paar einzukapseln. Ich kann eine Funktion schreiben, diesen Ausdruck

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

Nun ist der oben Lambda-Fang nur combine f g. Ich habe zwei Fragen.

  1. Ich bin interessiert zu wissen, ob es eine Standardbibliotheksfunktion gibt, die das tut, die ich gerade nicht finden kann.
  2. Aus Neugier möchte ich diese Funktion in Punkt-freien Stil umschreiben, aber ich habe eine Menge Probleme damit.

Antwort

12
  1. Control.Arrow hat die Funktion (&&&) dafür. Es hat einen "allgemeineren" Typ, was leider bedeutet, dass Hoogle es nicht findet (vielleicht sollte dies als ein Fehler in Hoogle betrachtet werden?).

  2. Normalerweise können Sie diese Art der Sache automatisch mit pointfree, die lambdabot in #haskell hat als ein Plugin haben.

Zum Beispiel:

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

Wo liftM2 mit der (r ->) Instanz Monad hat (a -> b -> c) -> (r -> a) -> (r -> b) -> r -> c geben. Natürlich gibt es viele andere Möglichkeiten, diesen Punkt frei zu schreiben, abhängig davon, welche Primitive du erlaubst.

+0

Danke für die kurze Antwort, und Dank für den Hinweis mich pointfree. – bshourd

12

Ich bin interessiert zu wissen, ob es eine Standardbibliotheksfunktion gibt, die das tut, die ich gerade nicht finden kann.

Es ist einfach, weil die Typklasse zu verpassen, aber look at Control.Arrow. Plain Arrow s kann nicht curiert oder angewendet werden, daher sind die Arrow Kombinatoren pointfree. Wenn Sie sie (->) spezialisieren, finden Sie diejenige, die Sie wollen, ist dies:

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

Es gibt noch andere, ähnliche Funktionen wie die äquivalente Operation für Either, die (->) spezialisiert sieht wie folgt aus:

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

Das ist das gleiche wie either.

Aus Neugier möchte ich diese Funktion in Punkt-frei-Stil umschreiben, aber ich habe eine Menge Probleme damit.

Da Sie eine Eingabe sind duplizieren, müssen Sie eine Möglichkeit, dass pointfree zu tun - die häufigste Art und Weise ist über die Applicative oder Monad Instanz für (->), zum Beispiel \f g ->(,) < $ > f < *> g . Dies ist im Wesentlichen eine implizite, inline Reader Monade, und das Argument, das aufgeteilt wird, ist der "Umgebungs" -Wert. Mit diesem Ansatz wird join f xf x x, pure oder return werden const, fmap wird (.) und (<*>) wird die S combinator\f g x -> f x (g x).

+2

Ein Teil des Grundes, warum die Control.Arrow-Funktionen schwer zu übersehen sind, ist, dass Hoogle Typvariablen nicht mit '->' vereinheitlicht, auch wenn die Arten übereinstimmen, also [Hoogling for '(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)) findet "(&&&)" nicht. ([Hoogling für 'fab -> fac -> fa (b, c)'] (http://www.haskell.org/hoogle/?q=f+a+b+-%3E+f+a+c+- % 3E + f + a + (b% 2Cc) funktioniert ebenso wie (mit einer Warnung) [Hoogling für '(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

Danke euch beiden dafür, das ist genau das, was ich wissen wollte. Danke Antal, dass er auf die 'a ~> b'-Syntax für Hoogle hingewiesen hat, von der ich nichts wusste. – bshourd

6

Es gibt eigentlich einige Möglichkeiten, dies zu tun. Die gängigste Methode ist die (&&&) Funktion von Control.Arrow zu verwenden:

f &&& g 

jedoch oft Sie mehr Funktionen haben oder das Ergebnis eine andere Funktion zu übergeben, in diesem Fall ist es viel bequemer ist applicative Stil zu verwenden. Dann

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

wird

liftA2 (+) f g 

Wie bereits erwähnt diese mit mehr als einer Funktion verwendet werden kann:

liftA3 zip3 f g h 
+0

Danke , speziell für die "Verwendung mit mehr als einer Funktion" Erklärung. – bshourd

+1

Und diese können natürlich mit '<$>' und '<*>' überschrieben werden: 'zip3 <$> f <*> g <*> h' Manchmal ist dies klarer als mit' liftA * '. –