2013-05-21 18 views
15

Manchmal möchten Sie eine Liste von Tupeln in ein Tupel mit verschiedenen Faltfunktionen falten. Zum Beispiel, um eine Liste von runState-Ergebnissen zusammenzuhalten, um einen (in gewissem Sinne) kombinierten Zustand und ein kombiniertes Ergebnis zu erhalten.Verwenden von Pfeilen zum Falten einer Liste von Tupeln

Betrachten Sie die folgende Umsetzung:

wish :: (a -> a' -> a) -> (b -> b' -> b) -> (a,b) -> [(a', b')] -> (a,b) 
wish lfn rfn x xs = foldl (\(a,b) -> (lfn a) *** (rfn b)) x xs 

Obwohl es funktioniert, ich fühle mich unwohl zu diesem Lambda. lfn *** rfn an sich hat eine Art von (a,b) -> (a -> a', b -> b'), die ich nicht finden kann eine Möglichkeit, auf ein Tupel ordnungsgemäß anwenden, ohne jemals auf Mustererkennung zurückgreifen. Gibt es eine klare und elegante Art, die ich vermisse? Es könnte eine Bibliotheksfunktion vom Typ (a,a') -> (a -> a, a' -> a') -> (a, a') oder ein ganz anderer Ansatz sein, vielleicht.

+2

Irgendeine Art von BiApplicative-Klasse würde tun .. Es gibt wahrscheinlich einen irgendwo im Hack, aber ich werde es anderen überlassen, um zu zeigen, welche gut und nicht veraltet sind. – Carl

+0

http://squing.blogspot.com/2008/11/beautiful-folding.html und seine Instantiierung auf Hackage, http://hackage.haskell.org/package/ZipFold –

Antwort

9

Control.Arrow nicht viel Aufmerksamkeit auf höhere Funktionen. Was Sie wirklich wollen, ist eine Funktion foo :: (a -> a' -> a'') -> (b -> b' -> b'') -> (a,b) -> (a',b') -> (a'',b''), das Analog von (***) für Funktionen von Arity 2. Es gibt eine solche Funktion in Data.Biapplicative (aus dem Paket bifunctor), die die etwas allgemeinere Signatur hat biliftA2 :: Biapplicative w => (a -> b -> c) -> (d -> e -> f) -> w a d -> w b e -> w c f. Da es eine Biapplicative-Instanz für Zwei-Elemente-Tupel gibt, ist das alles, was Sie brauchen.

Die einzige Beschwerde, die ich gegen Ihren Code sehen kann, ist, dass es das currying des Lambdas nicht offensichtlich ist; Ich könnte die explizitere \(a,b) (a',b') -> (lfn a a', rfn b b') bevorzugen.

Notizen bearbeiten: Ich war zu dem Schluss gekommen, dass die benötigte Funktion nicht existierte, und schlug vor, sie zu definieren; angespornt durch Carls Kommentar, fand ich den in Biapplicative (die allgemeinere Typus-Signatur hatte Hoogle daran gehindert, sie unter meiner vorgeschlagenen Signatur zu finden).

+0

Gehen für manuelle Tuple-Dekomposition mit '\ (a , b) (a ', b') -> ... 'trotzt irgendwie dem ganzen Zweck, ein ausgefallenes Konzept zu benutzen, um einen allmächtigen Einzeiler zu schreiben. Danke für den Hinweis auf Biapplicative, ich werde mich darum kümmern. –

+0

Mein Punkt war, dass, obwohl Biapplicative '(<<**>>)' den Typ hat, den Sie anwenden müssen "(lfn *** rfn)", der Aufruf von Pfeilen scheint hier fehl am Platz zu sein. Aber das ist nur meine Intuition; der pfeilbasierte Ansatz ist korrekt, wenn nicht unbedingt klar. Aber ich bevorzuge '(lfn \' biLiftA2 \ 'rfn)' zum expliziten Lambda. – isturdy

Verwandte Themen