Hibakezelés

Az M-kifejezés kiértékelésének eredménye az alábbi eredmények egyikét eredményezi:

  • Egyetlen érték jön létre.

  • Hiba lépett fel, amely azt jelzi, hogy a kifejezés kiértékelésének folyamata nem tudott értéket létrehozni. A hiba egyetlen rekordértéket tartalmaz, amellyel további információt kaphat arról, hogy mi okozta a hiányos értékelést.

A hibák egy kifejezésen belülről is felmerülhetnek, és egy kifejezésen belülről is kezelhetők.

Hibák elhárítása

A hibafelemelés szintaxisa a következő:

hibafelemelés-kifejezés:
      errorKifejezés

A szöveges értékek a hibaértékek rövidítésére használhatók. Például:

error "Hello, world" // error with message "Hello, world"

A teljes hibaértékek rekordok, és a Error.Record függvény használatával hozhatók létre:

error Error.Record("FileNotFound", "File my.txt not found",
     "my.txt")

A fenti kifejezés egyenértékű a következő kifejezéssel:

error [ 
    Reason = "FileNotFound", 
    Message = "File my.txt not found", 
    Detail = "my.txt" 
]

Ha hiba lép fel, az aktuális kifejezésértékelés leáll, a kifejezés-kiértékelési verem pedig visszateker, amíg az alábbiak valamelyike nem következik be:

  • A program egy rekordmezőt, szakasztagot vagy let változót – együttesen: bejegyzést – ér el. A bejegyzés hibaként van megjelölve, a hibaértéket ezzel a bejegyzéssel menti, majd propagálja. A bejegyzéshez való későbbi hozzáférés azonos hibát fog eredményezni. A rekord, a szakasz vagy a let kifejezés egyéb bejegyzéseit nem feltétlenül érintik (kivéve, ha egy korábban hibaként megjelölt bejegyzéshez férnek hozzá).

  • A legfelső szintű kifejezés el van érve. Ebben az esetben a legfelső szintű kifejezés kiértékelésének eredménye érték helyett hiba.

  • A try kifejezés el van érve. Ebben az esetben a rendszer rögzíti és visszaadja a hibát értékként.

Hibák kezelése

Egy hibakezelési kifejezés (nem hivatalos nevén "próbakifejezés") a következő hibák kezelésére szolgál:

error-handling-expression:
      tryprotected-expression error-handleropt
védett kifejezés:
      Kifejezés
hibakezelő:
      egyéb záradék
      catch-clause
egyéb záradék:

      otherwisealapértelmezett kifejezés
alapértelmezett kifejezés:
      Kifejezés
fogási záradék:
      catchcatch-function
catch-function:
      (parameter-nameopt)=>function-body

A hibakezelési kifejezés hibakezelő nélkül történő kiértékelésekor az alábbiak érvényesek:

  • Ha a védett kifejezés kiértékelése nem eredményez hibát, és x értéket eredményez, a hibakezelési kifejezés által előállított érték az alábbi űrlap rekordja:
    [ HasErrors = false, Value = x ]
  • Ha a védett kifejezés kiértékelése e hibaértéket eredményez, a hibakezelési kifejezés eredménye az alábbi űrlap rekordja:
    [ HasErrors = true, Error = e ]

A hibakezelési kifejezés hibakezelővel való kiértékelésekor az alábbiak érvényesek:

  • A védett kifejezést a hibakezelő előtt kell kiértékelni.

  • A hibakezelőt akkor és csak akkor kell kiértékelni, ha a védett kifejezés kiértékelése hibát jelez.

  • Ha a védett kifejezés kiértékelése hibát jelez, a hibakezelési kifejezés által előállított érték a hibakezelő kiértékelésének eredménye.

  • A hibakezelő kiértékelése során felmerülő hibák propagálása megtörténik.

  • Ha a kiértékelendő hibakezelő egy catch-záradék, a catch-függvény meghívása történik. Ha a függvény elfogad egy paramétert, a hibaérték lesz átadva annak értékeként.

Az alábbi példa egy hibakezelési kifejezést mutat be abban az esetben, ha nem merül fel hiba:

let
    x = try "A"
in
    if x[HasError] then x[Error] else x[Value] 
// "A"

Az alábbi példa egy hiba felvetését és kezelését mutatja be:

let
    x = try error "A" 
in
    if x[HasError] then x[Error] else x[Value] 
// [ Reason = "Expression.Error", Message = "A", Detail = null ]

Az előző példa kisebb szintaxissal újraírható egy catch-záradék és egy paramétert elfogadó catch-függvény használatával:

let
    x = try error "A" catch (e) => e
in
    x
// [ Reason = "Expression.Error", Message = "A", Detail = null ]

A próbakifejezés által kezelt hibák alternatív értékre való lecserélésére más záradék használható:

try error "A" otherwise 1 
// 1

A nullaparaméteres catch-függvényt tartalmazó catch-záradék tulajdonképpen egy hosszabb, alternatív szintaxis az egyébként záradékhoz:

try error "A" catch () => 1 
// 1

Ha a hibakezelő is hibát jelez, akkor a teljes próbakifejezés is:

try error "A" otherwise error "B" 
// error with message "B"
try error "A" catch () => error "B" 
// error with message "B"
try error "A" catch (e) => error "B" 
// error with message "B"

Hibák a rekordban és az inicializálók engedélyezése

Az alábbi példa egy rekord inicializálóját mutatja be egy olyan mezővel A , amely hibát jelez, és két másik mező B és C. A mező B nem kezeli az általa kiváltott Ahibát, de C igen. A végleges mező D nem fér hozzá A , ezért a hiba Anem érinti.

[ 
    A = error "A", 
    B = A + 1,
    C = let x =
            try A in
                if not x[HasError] then x[Value]
                else x[Error], 
    D = 1 + 1 
]

A fenti kifejezés kiértékelésének eredménye:

[ 
    A = // error with message "A" 
    B = // error with message "A" 
    C = "A", 
    D = 2 
]

Az M-ben a hibakezelést a lusta mező inicializálásának és a halasztott lezárási értékelések hatásának kezeléséhez a hibák okához közel kell elvégezni. Az alábbi példa egy hiba kifejezéssel történő kezelésének sikertelen kísérletét try mutatja be:

let
    f = (x) => [ a = error "bad", b = x ],
    g = try f(42) otherwise 123
in 
    g[a]  // error "bad"

Ebben a példában a definíció g a híváskor ffelmerülő hiba kezelésére szolgál. A hibát azonban egy mező inicializálója okozza, amely csak akkor fut, ha szükséges, és így a rekord f-ből való visszaadása és a try kifejezésen keresztül történő továbbítása után.

Nem implementált hiba

Egy kifejezés fejlesztése közben előfordulhat, hogy a szerző kihagyja a kifejezés bizonyos részeinek implementálását, de továbbra is szeretné végrehajtani a kifejezést. Ennek az esetnek az egyik módja, ha hibát jelez a nem felügyelt részeknél. Például:

(x, y) =>
     if x > y then
         x - y
     else
         error Error.Record("Expression.Error", 
            "Not Implemented")

A három pont szimbólum (...) a parancsikonként errorhasználható.

nem implementált kifejezés:
      ...

A következők például egyenértékűek az előző példával:

(x, y) => if x > y then x - y else ...