2013-03-14 9 views
7

Nehmen wir an, ich habe eine Funktion, die einige Berechnungen mit mehreren Mustern durchführt; implementiert in Form von Mustererkennung.Erlaubt Haskell einen Ausdruck für mehrere Mustervergleiche?

Die meisten dieser Muster tun (zusammen mit anderen Dingen, die voneinander verschieden sind) eine Behandlung auf einem Parameter, für den ich eine intermediäre Variable in einem let Ausdruck verwende. Aber ich finde es wirklich überflüssig, die gleiche let auf vielen Mustern zu haben, und ich frage mich, ob es eine Möglichkeit gibt, eine let für mehrere Muster zu definieren? Hier

ist ein Beispiel für meine dupliziert let:

data MyType a = Something a | Another Int [a] 

myFunc (Something x) = -- return something, this isn't the point here 
myFunc (Another 0 xs) = 
    let intermediary = some $ treatment xs 
    in doSthg intermediary 1 
myFunc (Another 1 (x:xs)) = 
    let intermediary = some $ treatment xs 
    in doSthg1 intermediary 1 x 
myFunc (Another 2 (x:x':xs)) = 
    let intermediary = some $ treatment xs 
    in doSthg2 intermediary 2 x x' 

Sie können sehen, dass der Parameter xs ist immer vorhanden, wenn ich es für intermediary verwenden und diese faktorisiert werden kann. Es könnte leicht mit Hilfe einer Hilfsfunktion erreicht werden, aber ich frage mich, ob das, was ich frage, ohne einen möglich ist. Bitte versuche es für Anfänger einfach zu halten, und ich hoffe, dass mein Beispiel klar genug ist.

+2

Nein! Muss eine separate Funktion verwenden und sie als Parameter explizit übergeben, um wiederholten Code herauszufiltern. Soweit Haskell betroffen ist, sind die obigen Vorkommen von "xs" völlig unterschiedliche Variablen (weil sie unterschiedliche Bindungsstellen haben). – luqui

+0

Danke! Jetzt habe ich eine andere Frage: Haben Sie beabsichtigt, dass die dritte und vierte Gleichung niemals übereinstimmen? Weil 'xs' zu irgendeiner Liste passt ... Haben Sie die Reihenfolge der Gleichungen umgekehrt? – yatima2975

+0

Ich habe dies geschrieben, um zu verdeutlichen, dass 'xs' aus Mustererkennung in mehreren Mustern extrahiert wird, aber nicht immer die gleiche Bedeutung hat (sonst hätte Mustervergleich kein Interesse: es würde nur ein Muster geben). Was damit im Beispiel gemacht wird, ist nicht wichtig; aber in meinem Code wird "y" durch echte Werte ersetzt, damit die späteren Muster übereinstimmen. Aber du hast wieder Recht, also werde ich es mit einem konkreten Typ bearbeiten, um das Ganze verständlicher zu machen. –

Antwort

7

Dieses insbesondere Problem kann umgangen werden, wie folgt:

myFunc2 (Something x) = returnSomething x 
myFunc2 (Another n ys) = 
    let xs = drop n ys 
     x = head ys 
     x' = head (tail ys) 
     intermediate = some $ treatment xs 
    in case n of 
     0 -> doSomething intermediate n 
     1 -> doSomething1 intermediate n x 
     2 -> doSomething2 intermediate n x x' 

Dank lazy evaluation x und x' wird nur dann, wenn ihr Wert benötigt wird, bewertet werden.

Allerdings - und das ist eine große jedoch! - Ihr Code wird einen Laufzeitfehler geben, wenn Sie versuchen, myFunc2 (Another 2 []) (und doSomething2 tatsächlich x!) aufrufen, denn um herauszufinden, was x ist, müssen wir head ys auswerten - und das wird für eine leere Liste abstürzen. Der Code, den Sie als Beispiel angegeben haben, wird auch nicht funktionieren (ein weiterer Laufzeitfehler) für Another 2 [], da es kein passendes Muster gibt, aber dort ist es einfacher, einen Fallfall zu liefern.

Dies ist möglicherweise kein Problem, wenn Sie die Eingabe steuern und immer sicherstellen, dass die Liste in Another lang genug ist, aber es ist wichtig, dieses Problem zu beachten!

+0

Dies ist effektiv kein Problem in meinem Code, da 'andere' Objekte nicht mit leeren Listen erstellt werden können. +1, tut es den Trick sehr gut –

+0

@ tehinternetsismadeofcatz: Das ganze Problem hat als eine starke 'Interpreter für eine Stack-Sprache'-Gefühl, so, wenn Sie richtig kompilieren, werden Sie richtig laufen - das Typ-System ist einfach nicht (aber es ist nahe!) stark genug, um auszudrücken, was du über die Eingänge * weißt *. Sie könnten auch erwägen, Ihren 'MyType' zu ​​ändern, um die Dinge, die Sie über die Argumente wissen, deutlicher auszudrücken, aber das ist eine Menge Arbeit ... – yatima2975