2015-12-21 19 views
6

Ich versuche, eine Bibliothek von JS portieren, und ich habe zu einer Funktion, die entweder eine Zeichenfolge oder eine Liste von Zeichenfolgen nehmen kann. Wenn eine Zeichenfolge angegeben wird, wird sie in eine Liste von Zeichenfolgen aufgeteilt und dann so fortgesetzt, als ob sie an erster Stelle übergeben wurde.Können Sie eine Funktion in Elm mehr als einen Typ nehmen? Kannst du eine überladene Funktion haben?

Ich kann es tun, indem ich meinen eigenen Typ definiere, aber es macht die API hässlich und erfordert ein benutzerdefiniertes Type-Präfix für Ihre Daten.

Hier ist, was ich habe:

type DocumentBody = Raw String | Words List String 

tokenize: DocumentBody -> List String 
tokenize s = 
    case s of 
     Raw str_body -> String.split " " str_body |> (List.map String.toLower) 
     Words list_body -> List.map String.toLower list_body 

-- Tests 

tests = 
    suite "Tokenizer" 
    [ test "simple" <| assertEqual ["this", "is", "a", "simple", "string"] 
            <| tokenize (Raw "this is a simple string") 

    , test "downcasing tokens: string" <| assertEqual ["foo", "bar"] 
                 <| tokenize (Raw "FOO BAR") 

    , test "downcasing tokens: list of str" <| assertEqual ["foo", "bar"] 
                  <| tokenize (Words ["Foo", "BAR"]) 
    ] 

Letztlich glaube ich nicht, dass der Port diese Art von Verhalten unterstützen sollte, aber wie wollen Sie Mustererkennung nur auf den Aufzählungen der Art statt benötigt das Präfix Raw oder Words in meinem Beispiel?

Antwort

4

Nein, Sie können Funktionen in Ulm nicht überlasten, so wie Sie es in anderen Sprachen können. Jede Funktion hat eine einzige Signatur. Wenn Sie möchten, dass eine Funktion einen Parameter akzeptiert, der von vielen Typen sein kann, funktioniert Ihre Lösung mit einem Union-Typ einwandfrei.

Sie sagen, dass es die API hässlich macht. Ich würde es nicht hässlich nennen. Vielleicht ist die Syntax der Typdeklaration oder der Case-Anweisungen nicht ansprechend, aber ich sage, gib ihr Zeit. Es wird auf dich wachsen. Da ist viel Kraft und Sicherheit. Du lässt nicht zu, dass der Code irgendwelche Annahmen macht, du bist gezwungen, mit jedem Szenario umzugehen, und es ist eine der Stärken, in einer Sprache wie Ulme zu arbeiten.

Ihr Mustervergleichscode ist angemessen. Sie können es darüber hinaus nicht verkürzen.

Zur gleichen Zeit kann ich den Schmerz der Umschreibung einer Javascript-Bibliothek und versuchen, über Ports von rohen Javascript zu verstehen. Sie schreiben die Dinge in einer viel strengeren Sprache um, und Sie werden nicht in der Lage sein, Funktionssignaturen zu kopieren, die in JavaScript alles und jeden akzeptiert haben. Aber wieder, das ist eine Stärke der Ulme, keine Schwäche. Nutzen Sie die Gelegenheit, die API zu straffen und Mehrdeutigkeiten zu beseitigen.

Wenn es um Ihr konkretes Beispiel geht, ist es für mich so, als gäbe es einige mögliche Alternativen, die über Ihre Lösung hinausgehen. Ich würde argumentieren, dass die tokenize Funktion zu viel verspricht, um damit anzufangen; es ist zu zweideutig. Wenn ich Code in funktionale Sprachen schreibe, halte ich die Dinge lieber klein und zusammensetzbar. Für mich sollte es wirklich zwei getrennte Funktionen mit jeweils einem bestimmten Zweck geben.

+0

"... du wirst nicht in der Lage sein, Funktionssignaturen zu duplizieren ..." oder vielmehr, dupliziere das komplette Fehlen von ihnen;) –

+0

auf deinen Punkt, jetzt muss der Anrufer wissen, was ein 'DocumentBody' ist Da dies der Typ ist, den diese Funktion benötigt, ist es sinnvoll, ihnen die Präfixe 'Raw' und' Words' zu geben. –

+0

Richtig, und das ist nichts, was über Ports sauber gemacht wird, also würde ich mich darauf konzentrieren, es aufzuteilen getrennte Funktionen. –