2014-01-27 26 views
6

Ich habe eine Liste von ganzen Zahlen basierend auf Buchstaben. Zum Beispiel:Faltung in Haskell, mit mehr als einer Funktion

let charlist = map (ord) "ABCDEF" 

charlist würde dann wie folgt aussehen:

[65,66,67,68,69,70] 

ich auch eine Liste mit drei Funktionen: (+), (-) und (*). Die Liste in diesem Beispiel sieht wie folgt aus

let funclist = [(+), (-), (*)] 

ich die Funktionen um zwischen den Elementen in charlist anwenden möchten (wenn es mehr „Räume“ in charlist sind, als es Elemente in funclist, Sie anfangen von Anfang funclist) und den Endwert von links nach rechts berechnen, wie folgt aus:

s = ((((((65) + 66) - 67) * 68) + 69) - 70) 

ich dachte über die Verwendung von foldl, b ut foldl scheint nur mit einer Funktion zu arbeiten. Gibt es einen anderen Weg, dies zu tun? Ich möchte diesen gesamten Prozess möglichst in einer Funktion zusammenfassen, obwohl dies keine Voraussetzung ist.

+1

Ich schlage vor, Sie zu implementieren versuchen, Dazu wird zuerst Mustererkennung und explizite Rekursion verwendet. Sobald Sie eine Lösung gefunden haben, die funktioniert, ist noch Zeit zu sehen, ob sie dem Muster für eine Funktion höherer Ordnung wie "foldl" entspricht. – kosmikus

+1

Sie können 'cycle' verwenden, um die Funktion zu implementieren, die Sie am Anfang von' funclist' neu starten, wenn keine Elemente mehr vorhanden sind. – kosmikus

Antwort

6

Während foldl nur eine Funktion anwenden können, können Sie verschiedene Funktionen in Ihre Daten haben. Der Trick dabei ist, die entsprechende +, - oder * Funktion an Ihre Daten anzuhängen. Sie sind nach rechts ab Beginn:

funclist = [(+), (-), (*)] 

Aber jetzt läßt eine unendliche Version der obigen Liste machen, wie [(+), (-), (*), (+), (-), (*)...]

infinite_funclist = cycle funclist 

Lassen die Zahlen weisen wir hier falten fahren.first ist in diesem Fall 65, rest ist [66..70]

(first:rest) = [65..70] 

Jetzt zip wir zusammen rest und infinite_funclist[(66,(+)), (67,(-)), (68,(*)), (69,(+)), (70,(-))] zu bekommen. Wir beginnen mit first, und für jedes neue Element, wenden wir die Operation, die auf den aktuellen Wert im zweiten Teil des aktuellen Tupels ist und dem ersten Teil in etwa so:

result = foldl' (\acc (v, f) -> acc `f` v) first (zip rest infinite_funclist) 

Wenn wir das Ergebnis drucken möchten wir Dazu kann etwa so:

main = print result 

(Link zum Code here)

+0

Vielen Dank dafür! Das funktioniert perfekt. Einfache Lösung mit einer guten Erklärung, die es sogar einem Neuling wie mir möglich macht, zu verstehen. ;) – Saser

4

Im Wesentlichen ist dies ein Reißverschluss statt eine Falte. Netteste wäre

> zipWith ($) (Zyklus funclist) charlist
[(65+), (66-), (67 *), (68+), (69-), (70+)]

aber wegen der links Assoziativität und ersten Elements müssen wir es ein bisschen mehr wortreich

> lassen ptApplied = Schwanz tun. zipWith (($). Flip) (Zyklus funclist) $ charlist
ptApplied = [(+66), (67 subtrahieren), (* 68), (+69), (subtrahieren 70)]

erst dann kommt die Falte

> foldl‘(Flip ($)) (Kopf charlist) ptApplied

0

Wer sagt, man kann nicht "passieren Variablen" foldl?

Prelude> let f = [(+), (-), (*)] 

Prelude> let c = [65,66,67,68,69,70] 

Prelude> foldl (\(a,i) val -> ((f!!(mod i 3)) a val,i + 1)) (head c,0) (tail c) 
(4351,5) 
1

Sie können immer mehr Informationen durch den Akkumulator des Falzes übergeben, die durch Ihre einzige Funktion zu verhalten verwendet werden können, als ob es eine andere Funktion jedes Mal war. Der einfachste Weg, dies zu tun, besteht darin, die aktuelle Liste von Funktionen, die durch den Rest der Liste im Akkumulator angewendet werden sollen, zu übergeben.

Prelude Data.List> snd $ foldl' (\(f:fs, acc) x -> (fs, f acc x)) 
           ((+):cycle funclist, 0) [65,66,67,68,69,70] 
4351 

(I eingefügt ein zusätzliches (+) auf der Vorderseite funclist, so dass die „echte“ Plus zwischen 65 und 66, statt zwischen dem Anfangsspeicher 0 und 65 kommt)

+0

Ich mag deine Antwort; Es half mir, meine Idee zu vereinfachen. –

Verwandte Themen