Äquivalent für ein Listenverständnis mit mehreren for-Klauseln zuordnen / reduzieren

8

Ich möchte ein funktionelles Äquivalent der Listen-Comprehensions schreiben, die nur Funktionen höherer Ordnung und ohne Nebenwirkungen verwenden. Ich tue dies ausschließlich zu Lernzwecken. Ich weiß, dass die Listenkomprehensionen Pythonic sind. In Python ist map(f, xs) gleichbedeutend mit [f(x) for x in xs] . Aber was sind die Entsprechungen darunter?

  • A: [f(x, y) for x in xs for y in ys]
  • B: [f(x, y) for x in range(1, 5) for y in range(x, 5)]

map gibt nur Listen gleicher Länge zurück. reduce ist allgemeiner, Sie können map und filter darauf implementieren.

%Vor%

Daher kann A wie folgt implementiert werden:

%Vor%

Aber das verallgemeinert sich nicht auf & gt; 2 für Klauseln. Und B ist noch komplizierter, da die Iterationsvariable aus der 1. for-Klausel im 2. Satz verwendet wird. Wie schreibe ich eine Funktion (oder einen Satz von Funktionen), die Listenverständnisfunktionalität implementiert?

    
Mirzhan Irkegulov 28.02.2014, 09:40
quelle

2 Antworten

11

Dies ist das Muster einer Monade , speziell der Listen-Monade. In vielen Sprachen sind Monaden hinter irgendeiner Art von syntaktischem Zucker verborgen, wie C # 's LINQ , Scalas Notation oder, in noch mehr Sprachen, (Multi-) Listen-Comprehensions (wie hier in Python).

Der Schlüsselbegriff für die Übersetzung von jeder dieser zuckerhaltigen Syntax in gewöhnliche Funktionen ist (im speziellen Fall von Listen) eine Funktion vom Typ ([a], a -> [b]) -> [b] , die der wesentliche Teil der Definition einer Monade ist. Diese Funktion ist unter verschiedenen Namen bekannt, z. (>>=) oder "bind", flatMap oder concatMap oder selectMany .

Für den Fall von Listen ist concatMap oder flatMap wahrscheinlich der beste Name, weil er das ist: eine Funktion, die Listen zurückgibt, einer Liste zuordnen und eine Liste von Listen geben; dann glätten Sie diese Liste.

Nun zu etwas konkreter 1 :

%Vor%

Testen:

%Vor%

Und mehr Spaß:

%Vor%

Schließlich sollte beachtet werden, dass obwohl eine map -ähnliche Funktion immer für eine Monade benötigt wird, im Allgemeinen reduce nicht genug ist - was tatsächlich benötigt wird, ist eine verallgemeinerte "Abflachung" Operation join , mit einem Typ wie m<m<a>> (unter Verwendung der Template / Generics-Syntax), wobei m der Typ ist der betreffenden Monade.

1 Wie in den Kommentaren erwähnt, kann dies auch als concatMap = lambda xs, f: chain.from_iterable(map(f, xs)) definiert werden, indem itertools und die Identität (>>=) ≡ join . fmap verwendet werden.

    
phg 01.03.2014, 17:41
quelle
2

Sie können itertools.starmap und itertools.product für den Fall A :

%Vor%

Demo:

%Vor%     
Ashwini Chaudhary 28.02.2014 09:44
quelle