i

Fachkonzept - Fehlerbehandlung mit Result

Fehlerarten als Daten

In der Programmiersprache Elm werden Fehler als Daten behandelt. Für einfache Fehlersituationen, bei denen es nur darum geht, ob eine Berechnung erfolgreich war oder nicht, ist der Datentyp Maybe geeignet. Für komplexere Fehlersituationen, bei denen es darum geht, unterschiedliche Fehlerarten zu unterscheiden, ist der Datentyp Result geeignet.

Der Datentyp Result

Der Datentyp Result ist so definiert:

type Result error value
    = Ok value
    | Err error

Die Typvariablen error und value können dabei mit beliebigen vordefinierten Typen oder selbst definierten Typen konkretisiert werden. Die Typvariable error steht dabei für die Fehlerart, die in einer Fehlersituation vorliegt. Die Typvariable value steht dabei für den Datentyp, der bei einer erfolgreichen Berechnung vorliegt.

Beispiel: Result String Int

Wenn man Result mit den Typen String und Int konkretisiert, dann erhält im Fehlerfall einen Wert wie z.B. Err "Fehler: ungültige Zahl", der die Fehlersituation beschreibt, und im Erfolgsfall einen Wert wie z.B. Ok 2, der die Ergebniszahl enthält.

Man könnte z.B. eine Funktion teilePositiv definieren, die nur für positive Zahlen definiert sein soll. Im Fehlerfall bekommt man einen Wert zurück, der die Fehlersituation beschreibt. Im Erfolgsfall bekommt man einen Wert zurück, der das Ergebnis der Berechnung enthält.

teilePositiv : Int -> Int -> Result String Int
teilePositiv zaehler nenner =
    if nenner == 0 then
        Err "Fehler: Division durch Null"

    else if zaehler < 0 || nenner < 0 then
        Err "Fehler: negative Zahl"

    else
        Ok (zaehler // nenner)

Die Funktion wird dann wie folgt benutzt:

> teilePositiv 10 2
Ok 5 : Result String Int
> teilePositiv 10 0
Err "Fehler: Division durch Null" : Result String Int
> teilePositiv (-10) 2
Err "Fehler: negative Zahl" : Result String Int
Selbst definierte Fehlerarten

Noch besser wäre es, wenn man die Fehlersituationen mit Hilfe von selbst definierten Datentypen beschreibt, damit die verschiedenen Fehlersituationen auch über die Fehlermeldungen hinaus klar voneinander zu unterscheiden sind.

type Fehlerart
    = DivisionDurchNull
    | NegativeZahl

Dann könnte man die Funktion teilePositiv wie folgt definieren:

teilePositiv : Int -> Int -> Result Fehlerart Int
teilePositiv zaehler nenner =
    if nenner == 0 then
        Err DivisionDurchNull

    else if zaehler < 0 || nenner < 0 then
        Err NegativeZahl

    else
        Ok (zaehler // nenner)

Die Funktion wird dann wie folgt benutzt:

> teilePositiv 10 2
Ok 5 : Result Fehlerart Int
> teilePositiv 10 0
Err DivisionDurchNull : Result Fehlerart Int
> teilePositiv (-10) 2
Err NegativeZahl : Result Fehlerart Int

Verarbeitung von Result-Werten

Auf die Werte Werte eines Result-Typs kann man mit Hilfe von Pattern Matching zugreifen:

divisionToString : Int -> Int -> String
divisionToString zaehler nenner =
    case teilePositiv zaehler nenner of
        Ok ergebnis ->
            "Ergebnis: " ++ String.fromInt ergebnis

        Err DivisionDurchNull ->
            "Fehler: Division durch Null"

        Err NegativeZahl ->
            "Fehler: negative Zahl"

Falls man die Fehlerfälle nicht unterscheiden möchte, kann man den konkreten Fehlerfall auch mit einem Wildcard-Pattern ignorieren:

divisionToString : Int -> Int -> String
divisionToString zaehler nenner =
    case teilePositiv zaehler nenner of
        Ok ergebnis ->
            "Ergebnis: " ++ String.fromInt ergebnis

        Err _ ->
            "Fehler: ungültige Eingabe"

Suche

v
8.2.2.9.5 Fachkonzept - Fehlerbehandlung mit Result
Kopieren durch Anklicken

Rückmeldung geben