Ich habe drei Funktionen, die das n-te Element einer Liste finden:
nthElement :: [a] -> Int -> Maybe a
nthElement [] a = Nothing
nthElement (x:xs) a | a <= 0 = Nothing
| a == 1 = Just x
| a > 1 = nthElement xs (a-1)
nthElementIf :: [a] -> Int -> Maybe a
nthElementIf [] a = Nothing
nthElementIf (x:xs) a = if a <= 1
then if a <= 0
then Nothing
else Just x -- a == 1
else nthElementIf xs (a-1)
nthElementCases :: [a] -> Int -> Maybe a
nthElementCases [] a = Nothing
nthElementCases (x:xs) a = case a <= 0 of
True -> Nothing
False -> case a == 1 of
True -> Just x
False -> nthElementCases xs (a-1)
Meiner Meinung nach ist die erste Funktion die beste Implementierung, weil sie am prägnantesten ist. Aber gibt es irgendetwas an den beiden anderen Implementierungen, das sie vorzuziehen wäre? Und im weiteren Sinne, wie würden Sie zwischen der Verwendung von Wachen, Wenn-Dann-Sonst-Anweisungen und Fällen wählen?
haskell
if-statement
case
Nuklearflut
quelle
quelle
case
Anweisungencase compare a 0 of LT -> ... | EQ -> ... | GT -> ...
case compare a 1 of ...
Antworten:
Aus technischer Sicht sind alle drei Versionen gleichwertig.
Abgesehen davon lautet meine Faustregel für Stile, dass Sie wahrscheinlich etwas tun , wenn Sie es so lesen können, als wäre es Englisch (gelesen
|
als "wann",| otherwise
als "anders" und=
als "ist" oder "sein") richtig.if..then..else
ist für den Fall, dass Sie eine binäre Bedingung oder eine einzelne Entscheidung haben, die Sie treffen müssen. Verschachtelteif..then..else
Ausdrücke sind in Haskell sehr selten, und stattdessen sollten fast immer Wachen verwendet werden.Jeder
if..then..else
Ausdruck kann durch einen Schutz ersetzt werden, wenn er sich auf der obersten Ebene einer Funktion befindet. Dies sollte im Allgemeinen bevorzugt werden, da Sie dann einfacher weitere Fälle hinzufügen können:case..of
Dies ist der Fall , wenn Sie mehrere Codepfade haben und jeder Codepfad von der Struktur eines Werts geleitet wird, dh über den Mustervergleich. Sie passen sehr selten aufTrue
undFalse
.Guards ergänzen
case..of
Ausdrücke. Wenn Sie also komplizierte Entscheidungen in Abhängigkeit von einem Wert treffen müssen, treffen Sie zuerst Entscheidungen in Abhängigkeit von der Struktur Ihrer Eingabe und dann Entscheidungen über die Werte in der Struktur.Übrigens. Machen Sie als Stiltipp immer eine neue Zeile nach a
=
oder vor a,|
wenn das Material nach dem=
/|
für eine Zeile zu lang ist oder aus einem anderen Grund mehr Zeilen verwendet:quelle
True
undFalse
" gibt es überhaupt eine Gelegenheit, wo Sie das tun würden? Schließlich kann diese Art von Entscheidung immer mit einemif
und auch mit Wachen getroffen werden.case (foo, bar, baz) of (True, False, False) -> ...
guard
Funktion erfordertMonadPlus
, aber wir sprechen hier von Wachen wie in| test =
Klauseln, die nicht verwandt sind.Ich weiß, dass dies eine Frage zum Stil für explizit rekursive Funktionen ist, aber ich würde vorschlagen, dass der beste Stil darin besteht, stattdessen vorhandene rekursive Funktionen wiederzuverwenden.
quelle
Dies ist nur eine Frage der Bestellung, aber ich denke, es ist sehr gut lesbar und hat die gleiche Struktur wie Wachen.
Letzteres braucht man nicht und wenn es keine anderen Möglichkeiten gibt, sollten auch Funktionen "Last-Resort-Fall" haben, falls Sie etwas verpasst haben.
quelle