【问题标题】:How to raise an exception that prints a message and returns a value?如何引发打印消息并返回值的异常?
【发布时间】:2013-03-30 23:46:15
【问题描述】:

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

如果给定的阈值是负数,您应该打印消息“错误:负阈值”并返回一个空列表。为此,请定义一个名为 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

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

【问题讨论】:

    标签: exception-handling sml


    【解决方案1】:
    • 首先,声明一个异常

      exception OutOfRangeException;
      
    • 定义将引发异常的函数:

      fun someFunc x =
        if x < 0 then 
          raise OutOfRangeException
        else [1,2,3,4] (*return some list*)
      
    • 最后,将通过打印消息并返回来处理异常的函数 和空列表:

    fun someFunc_test x=    
      (someFunc x) handle OutOfRangeException => (print "exception"; [])
    

    【讨论】:

    • 异常不需要是全局的。它只需要在处理它的代码范围内
    • 嗯,这不一定是好的做法。为用户隐藏异常可能有多种原因。例如,内部逻辑可以通过异常处理来实现,并且让用户访问异常可能会搞砸它。一般来说,只要异常在内部使用,就没有必要通过“全局”声明来污染环境。
    • 异常在 ML 和朋友中并不慢,因此与 Java 和其他人不同,它有时可能会导致处理控制流的简单而美观的方式。例如,我看到eight queen problem/puzzle 的一个非常简洁的解决方案,使用异常来控制控制流。
    【解决方案2】:

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

    exp_1 handle pat => exp_2
    

    因此,您正在寻找的是一种在exp_2 部分中执行多种操作的方法,特别是具有打印消息的副作用的方法。对于此类事情,您可以使用序列。序列具有以下形式(注意括号)

    (exp_1; ... ; exp_n) 
    

    它本身就是一个表达式。如下所示

    - (print "foo\n"; print "bar\n"; 42);
    foo
    bar
    val it = 42 : int
    

    从这里我们可以看出,序列的最终结果是 exp_n 的计算结果。

    由于 let 表达式中经常使用序列,因此可以写成以下(不带前面提到的括号)

    let dec in exp_1 ; ... ; exp_n end
    

    奖金信息

    序列实际上是一系列案例的派生形式(句法糖)。以下

    (expr_1 ; ... ; exp_n ; exp)
    

    等价于

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

    【讨论】:

    • 我相信这也被称为side-effecting
    猜你喜欢
    • 2014-02-10
    • 1970-01-01
    • 2010-11-06
    • 1970-01-01
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-30
    相关资源
    最近更新 更多