SML将字符串转换为具有错误捕获的int

时间:2016-02-23 23:26:18

标签: error-handling type-conversion sml

所以我想要做的是将一个字符串转换为一个int并做一些错误捕获它。我还想知道如果它失败了我会把它想要做的事情放在哪里。

我知道如何转换,但我不知道如何捕获它以及代码将在错误后跳转到哪里

我相信将其转换为Int.fromString(x)

的方法

谢谢。

2 个答案:

答案 0 :(得分:3)

SML有两种错误处理方法。一种是基于handle来引发错误而options来捕获错误,有点类似于错误处理在Python或Java等语言中的工作方式。它是有效的,但由此产生的代码往往会失去一些功能的味道。另一种方法基于Int.fromString的概念。由于string -> int option 的返回类型是

int option

使用基于选项的方法最有意义。

SOME nn,其中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