Processamento de Erros
O resultado da avaliação de uma expressão M produz um dos seguintes resultados:
Um único valor é produzido.
Um erro é gerado, indicando que o processo de avaliação da expressão não poderia produzir um valor. Um erro contém um único valor de registro que pode ser usado para fornecer informações adicionais sobre o que causou a avaliação incompleta.
Os erros podem ser gerados a partir de uma expressão e podem ser tratados a partir de uma expressão.
Suscitar erros
A sintaxe para gerar um erro é a seguinte:
expressão de aumento de erro:
error
expressão
Os valores de texto podem ser usados como abreviatura para valores de erro. Por exemplo:
error "Hello, world" // error with message "Hello, world"
Os valores de erro completos são registros e podem ser construídos usando a Error.Record
função:
error Error.Record("FileNotFound", "File my.txt not found",
"my.txt")
A expressão acima é equivalente a:
error [
Reason = "FileNotFound",
Message = "File my.txt not found",
Detail = "my.txt"
]
Gerar um erro fará com que a avaliação de expressão atual seja interrompida e a pilha de avaliação de expressão será desenrolada até que ocorra uma das seguintes situações:
Um campo de registro, membro de seção ou variável let — coletivamente: uma entrada — é alcançado. A entrada é marcada como tendo um erro, o valor do erro é salvo com essa entrada e, em seguida, propagado. Qualquer acesso subsequente a essa entrada causará um erro idêntico a ser gerado. Outras entradas do registro, seção ou expressão let não são necessariamente afetadas (a menos que acessem uma entrada marcada anteriormente como tendo um erro).
A expressão de nível superior é atingida. Nesse caso, o resultado da avaliação da expressão de nível superior é um erro em vez de um valor.
Chega-se a uma
try
expressão. Nesse caso, o erro é capturado e retornado como um valor.
Processar erros
Uma expressão de manipulação de erros (conhecida informalmente como "expressão try") é usada para lidar com um erro:
error-handling-expression:
try
opt pelo manipuladorde erros de expressão protegida
Expressão-protegida:
expressão
manipulador de erros:
cláusula contrária
Cláusula de captura
cláusula contrária:
otherwise
expressão-padrão
expressão-padrão:
expressão
Cláusula de captura:
catch
Função de captura
Função de captura:
(
nome-parâmetroopt =>
)
função-corpo
O seguinte vale ao avaliar uma expressão de manipulação de erros sem um manipulador de erros:
- Se a avaliação da expressão protegida não resultar em um erro e produzir um valor x, o valor produzido pela expressão de manipulação de erros será um registro da seguinte forma:
[ HasErrors = false, Value = x ]
- Se a avaliação da expressão protegida gerar um valor de erro e, o resultado da expressão de tratamento de erros será um registro da seguinte forma:
[ HasErrors = true, Error = e ]
O seguinte vale ao avaliar uma expressão de manipulação de erros com um manipulador de erros:
A expressão protegida deve ser avaliada antes do manipulador de erros.
O manipulador de erros deve ser avaliado se e somente se a avaliação da expressão protegida gerar um erro.
Se a avaliação da expressão protegida gerar um erro, o valor produzido pela expressão de manipulação de erros é o resultado da avaliação do manipulador de erros.
Os erros gerados durante a avaliação do manipulador de erros são propagados.
Quando o manipulador de erros que está sendo avaliado é uma cláusula catch, a função catch-é invocada. Se essa função aceitar um parâmetro, o valor do erro será passado como seu valor.
O exemplo a seguir ilustra uma expressão de manipulação de erros em um caso em que nenhum erro é gerado:
let
x = try "A"
in
if x[HasError] then x[Error] else x[Value]
// "A"
O exemplo a seguir mostra como gerar um erro e, em seguida, manipulá-lo:
let
x = try error "A"
in
if x[HasError] then x[Error] else x[Value]
// [ Reason = "Expression.Error", Message = "A", Detail = null ]
O exemplo anterior pode ser reescrito com menos sintaxe usando uma cláusula catch-com uma função catch-que aceita um parâmetro:
let
x = try error "A" catch (e) => e
in
x
// [ Reason = "Expression.Error", Message = "A", Detail = null ]
Uma cláusula de outra forma pode ser usada para substituir erros manipulados por uma expressão try por um valor alternativo:
try error "A" otherwise 1
// 1
Uma cláusula catch-com uma função catch-parâmetro zero é efetivamente uma sintaxe alternativa mais longa para uma cláusula de outra forma:
try error "A" catch () => 1
// 1
Se o manipulador de erros também gerar um erro, toda a expressão try também gera:
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"
Erros nos inicializadores de registro e permissão
O exemplo a seguir mostra um inicializador de registro com um campo A
que gera um erro e é acessado por dois outros campos B
e C
. O campo B
não lida com o erro gerado pelo A
, mas C
o faz. O campo D
final não acessa A
e, portanto, não é afetado pelo erro em A
.
[
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
]
O resultado da avaliação da expressão acima é:
[
A = // error with message "A"
B = // error with message "A"
C = "A",
D = 2
]
O tratamento de erros em M deve ser realizado próximo à causa dos erros para lidar com os efeitos da inicialização de campo preguiçoso e avaliações de fechamento diferido. O exemplo a seguir mostra uma tentativa malsucedida de manipular um erro usando uma try
expressão:
let
f = (x) => [ a = error "bad", b = x ],
g = try f(42) otherwise 123
in
g[a] // error "bad"
Neste exemplo, a definição g
destinava-se a lidar com o erro gerado ao chamar f
. No entanto, o erro é gerado por um inicializador de campo que só é executado quando necessário e, portanto, depois que o registro foi retornado de f e passado pela try
expressão.
Erro não implementado
Enquanto uma expressão está sendo desenvolvida, um autor pode querer deixar de fora a implementação para algumas partes da expressão, mas ainda pode querer ser capaz de executar a expressão. Uma maneira de lidar com esse caso é gerar um erro para as partes não implementadas. Por exemplo:
(x, y) =>
if x > y then
x - y
else
error Error.Record("Expression.Error",
"Not Implemented")
O símbolo de reticências (...
) pode ser usado como um atalho para error
.
expressão não implementada:
...
Por exemplo, o seguinte é equivalente ao exemplo anterior:
(x, y) => if x > y then x - y else ...