所以我想要做的是将一个字符串转换为一个int并做一些错误捕获它。我还想知道如果它失败了我会把它想要做的事情放在哪里。
我知道如何转换,但我不知道如何捕获它以及代码将在错误后跳转到哪里
我相信将其转换为Int.fromString(x)
的方法谢谢。
答案 0 :(得分:3)
SML有两种错误处理方法。一种是基于handle
来引发错误而options
来捕获错误,有点类似于错误处理在Python或Java等语言中的工作方式。它是有效的,但由此产生的代码往往会失去一些功能的味道。另一种方法基于Int.fromString
的概念。由于string -> int option
的返回类型是
int option
使用基于选项的方法最有意义。
SOME n
是n
,其中NONE
是整数,或者是Int.fromString
。如果函数Int.fromString
在尝试将字符串转换为整数时失败,则函数NONE
将返回后者。调用valOf
的函数可以显式测试SOME n
,并使用case
在返回值为fun squareString s =
case Int.fromString(s) of
SOME n => Int.toString (n * n) |
NONE => s ^ " isn't an integer";
形式的情况下提取值。或者,在某种程度上更具惯用性,您可以在string -> string
表达式中使用模式匹配。这是一个玩具示例:
- squareString "4";
val it = "16" : string
- squareString "Bob";
val it = "Bob isn't an integer" : string
此函数的类型为NONE =>
。典型输出:
fun squareString s =
case Int.fromString(s) of
SOME n => SOME (Int.toString (n * n))|
NONE => NONE;
请注意,启动string -> string option
的子句基本上是一个错误处理程序。如果您定义的函数无法处理此类错误,则可以通过降压。例如:
- squareString "4";
val it = SOME "16" : string option
- squareString "Bob";
val it = NONE : string option
这个类型{{1}}的输出现在看起来像:
{{1}}
这将使调用者有责任找出如何处理该选项。
答案 1 :(得分:2)
John解释的错误处理方法在StackOverflow问题'Unpacking' the data in an SML DataType without a case statement中详细说明。用例有点不同,因为它还涉及语法树,但同样的便利适用于较小的情况:
fun squareString s = Int.fromString s >>= (fn i => SOME (i*i))
假设您将>>=
运算符定义为:
infix 3 >>=
fun NONE >>= _ = NONE
| (SOME a) >>= f = f a
使用'一个选项进行错误处理的缺点是你必须考虑,每次你使用具有此返回类型的函数,它错了。这不是不合理的。这就像强制空检查一样。但它的代价是无法轻松编写您的函数(使用例如o
运算符)和许多嵌套的大小写的:
fun inputSqrt s =
case TextIO.inputLine TextIO.stdIn of
NONE => NONE
| SOME s => case Real.fromString s of
NONE => NONE
| SOME x => SOME (Math.sqrt x) handle Domain => NONE
一种解决方法是,只要所有函数都以相同的方式表达错误,就可以将这种常量错误处理构建到函数组合运算符中。使用'选项:
fun safeSqrt x = SOME (Math.sqrt x) handle Domain => NONE
fun inputSqrt () =
TextIO.inputLine TextIO.stdIn >>=
(fn s => Real.fromString s >>=
(fn x => safeSqrt x))
甚至更短时间应用Eta conversion:
fun inputSqrt () = TextIO.inputLine TextIO.stdIn >>= Real.fromString >>= safeSqrt
由于缺少输入,或输入未转换为 real ,或者因为它是负数,此函数可能会失败。当然,这种错误处理不够聪明,不能说错误是什么,因此您可能希望将函数扩展为使用'a option 来使用('a,'b):
datatype ('a, 'b) either = Left of 'a | Right of 'b
infix 3 >>=
fun (Left msg) >>= _ = Left msg
| (Right a) >>= f = f a
fun try (SOME x) _ = Right x
| try NONE msg = Left msg
fun inputLine () =
try (TextIO.inputLine TextIO.stdIn) "Could not read from stdIn."
fun realFromString s =
try (Real.fromString s) "Could not derive real from string."
fun safeSqrt x =
try (SOME (Math.sqrt x) handle Domain => NONE) "Square root of negative number"
fun inputSqrt () =
inputLine () >>= realFromString >>= safeSqrt
试试这个:
- inputSqrt ();
9
> val it = Right 3.0 : (string, real) either
- inputSqrt ();
~42
> val it = Left "Square root of negative number" : (string, real) either
- inputSqrt ();
Hello
> val it = Left "Could not derive real from string." : (string, real) either
- (TextIO.closeIn TextIO.stdIn; inputSqrt ());
> val it = Left "Could not read from stdIn." : (string, real) either