Exception handling 如何引发打印消息并返回值的异常?

Exception handling 如何引发打印消息并返回值的异常?,exception-handling,sml,Exception Handling,Sml,我们的教授让我们在作业中这样做: 如果给定的阈值为负,则应打印消息“错误:负阈值”,并返回空列表。为此,定义一个名为ThresholdOutOfRange的异常,如果阈值为负值,则提高该异常,并处理该异常以实现正确的行为 我不知道如何引发异常、返回值和打印错误消息。现在,我提出异常的代码只是异常的重要部分: fun getnearbylist(center, threshold, ziplist) = let exception ThresholdOutOfRange;

我们的教授让我们在作业中这样做:

如果给定的阈值为负,则应打印消息“错误:负阈值”,并返回空列表。为此,定义一个名为ThresholdOutOfRange的异常,如果阈值为负值,则提高该异常,并处理该异常以实现正确的行为

我不知道如何引发异常、返回值和打印错误消息。现在,我提出异常的代码只是异常的重要部分:

fun getnearbylist(center, threshold, ziplist) =
    let
      exception ThresholdOutOfRange;
      fun test_threshold(threshold, zip, nil) =nil
      |   test_threshold(threshold, zip, ziplist as x::xs) =
          if (threshold <0.0) then raise ThresholdOutOfRange
(*        [...skipped a long unrelated middle bit. most important is just knowing
              this function returns a string list...] *)
          else x::test_threshold(threshold, zip, xs)
    in
      test_threshold(threshold, center, ziplist)
      handle
      ThresholdOutOfRange => []
    end

因此,当引发异常时,我的代码将只返回一个空列表。据我所知,如果异常必须具有与所引发的函数相同的返回类型,我该怎么做才能返回空列表并打印错误消息?

正确的是,异常处理的结果类型必须与处理异常的表达式相同。换句话说,exp_1和exp_2在下面的代码中必须具有相同的类型,就像if表达式的then和else部分一样

exp_1 handle pat => exp_2
因此,您正在寻找一种在exp2部分中执行多种操作的方法,特别是具有打印消息的副作用的方法。对于这样的事情,你可以使用序列。序列具有以下形式注释括号

(exp_1; ... ; exp_n) 
let dec in exp_1 ; ... ; exp_n end
这本身就是一种表达。这在下文中得到了证明

- (print "foo\n"; print "bar\n"; 42);
foo
bar
val it = 42 : int
(expr_1 ; ... ; exp_n ; exp)
从这一点我们可以看出,序列的最终结果是经验的计算结果

由于let表达式中经常使用序列,因此可以在不使用前面提到的括号的情况下编写以下内容

(exp_1; ... ; exp_n) 
let dec in exp_1 ; ... ; exp_n end
奖金信息

序列实际上是一系列格的派生形式。以下

- (print "foo\n"; print "bar\n"; 42);
foo
bar
val it = 42 : int
(expr_1 ; ... ; exp_n ; exp)
相当于

case expr_1 of _ => 
  case ... =>
    case exp_n of _ => exp

异常处理的结果类型必须与处理异常的表达式相同,这是正确的。换句话说,exp_1和exp_2在下面的代码中必须具有相同的类型,就像if表达式的then和else部分一样

exp_1 handle pat => exp_2
因此,您正在寻找一种在exp2部分中执行多种操作的方法,特别是具有打印消息的副作用的方法。对于这样的事情,你可以使用序列。序列具有以下形式注释括号

(exp_1; ... ; exp_n) 
let dec in exp_1 ; ... ; exp_n end
这本身就是一种表达。这在下文中得到了证明

- (print "foo\n"; print "bar\n"; 42);
foo
bar
val it = 42 : int
(expr_1 ; ... ; exp_n ; exp)
从这一点我们可以看出,序列的最终结果是经验的计算结果

由于let表达式中经常使用序列,因此可以在不使用前面提到的括号的情况下编写以下内容

(exp_1; ... ; exp_n) 
let dec in exp_1 ; ... ; exp_n end
奖金信息

序列实际上是一系列格的派生形式。以下

- (print "foo\n"; print "bar\n"; 42);
foo
bar
val it = 42 : int
(expr_1 ; ... ; exp_n ; exp)
相当于

case expr_1 of _ => 
  case ... =>
    case exp_n of _ => exp
首先,声明一个异常:

定义将引发异常的函数:

首先,声明一个异常:

定义将引发异常的函数:


我相信这也被称为副作用我相信这也被称为副作用例外情况不需要是全局性的。它只需要在能够很好地处理它的代码范围内,这不一定是好的实践。为用户隐藏异常可能有多种原因。例如,内部逻辑可以通过异常处理来实现,而允许用户访问异常可能会使其出错。一般来说,只要异常只在内部使用,就没有必要通过在全球范围内声明它来污染环境。异常在ML和friends中并不慢,因此与Java和其他语言不同,它有时可能导致一种简单而漂亮的控制流处理方法。例如,我看到了一个非常简洁的解决方案,可以使用异常来控制控制流。异常不需要是全局的。它只需要在能够很好地处理它的代码范围内,这不一定是好的实践。为用户隐藏异常可能有多种原因。例如,内部逻辑可以通过异常处理来实现,而允许用户访问异常可能会使其出错。一般来说,只要异常只在内部使用,就没有必要通过在全球范围内声明它来污染环境。异常在ML和friends中并不慢,因此与Java和其他语言不同,它有时可能导致一种简单而漂亮的控制流处理方法。例如,我看到了一个非常简洁的解决方案,可以使用异常来控制控制流。