简体   繁体   English

SML中的引发/抛出异常

[英]Raise/throw exception in SML

Write two versions of the function power, the first version takes two integer arguments m and n and returns the value m^n 编写函数的两个版本,第一个版本使用两个整数参数m和n并返回值m ^ n

Note that both m and n can be any integers (positive or non-positive). 请注意,m和n都可以是任何整数(正数或非正数)。 The second version of the function is called (cpower mn) and it is the curried version. 该函数的第二个版本称为(cpower mn),它是当前版本。

Remark: if both m and n are Zero then an exception should be raised. 备注:如果m和n均为零,则应引发异常。

fun power(m,n) = if n=0 then 1 else m * power(m,n-1);

fun cpower (m,n) : int =
    if n = 0 then 1 else
    if n >= 0 then power(m,n) else
    if n < 0 then 1/power(m,n) else m * cpower (m,n-1);

How do I add so that this function throws an exception? 如何添加该函数引发异常?

  1. Your cpower function does not have the right type signature. 您的cpower函数没有正确的类型签名。 It isn't curried. 不咖喱。 A curried function with two arguments looks like: 具有两个参数的咖喱函数看起来像:

     fun cpower mn = ... 

    It has the type int → int → int as opposed to power 's type (int × int) → int . 它的类型为int→int→int ,与power的类型(int×int)→int相反。 Curried functions with two arguments are equivalent to functions with one argument that return a function with another argument. 具有两个参数的库里函数等效于具有一个参数的函数,该函数返回具有另一个参数的函数。 Eg 例如

     fun cpower m = (fn n => ...) 

    that can also be written 也可以写成

     val rec cpower = (fn m => fn n => ...) 
  2. Your current cpower function appears to have a special case for n<0 , but here you write 1/power(m,n) . 您当前的cpower函数对于n<0似乎有特殊情况,但是在这里您写1/power(m,n) But the / operator is not defined for integers which the rest of your program assumes through integer literals (0, 1) and if the result is a fraction below 1, it isn't in the domain of integers. 但是/运算符未定义为整数,程序的其余部分通过整数文字(0,1)来假定整数,并且如果结果是小于1的分数,则不在整数域中。

  3. Consider using pattern matching instead of if-then-else in both cases. 在两种情况下,请考虑使用模式匹配而不是if-then-else。 For the first power function it would look like: 对于第一个幂函数,它看起来像:

     fun naive_power (m, 0) = 1 | naive_power (m, n) = m * naive_power (m, n-1) 
  4. Your functions don't throw when both m and n are zero. 当m和n均为零时,函数不会抛出。 (Neither does my version that uses pattern matching.) You might want to write an additional if-then-else and throw if both m and n are zero, eg like, (我的使用模式匹配的版本也没有。)您可能想编写一个额外的if-then-else,如果m和n均为零,则抛出该异常,例如,

     fun power (m, 0) = 1 | power (m, n) = if n < 0 then raise Domain else m * power (m, n-1) 

    One bad thing about this function is that it will check if n < 0 at every single recursive call to itself when, really, you know that if it was positive the first time and the base case will catch it at 0, it won't be negative at any later stage. 这个函数的一个坏处是,当您真正知道您第一次知道它是否为正数并且基本情况将其捕获为0时,它将在每次对其自身进行递归调用时检查n < 0在以后的任何阶段都是负面的。 An elegant solution here is to wrap the recursive part of your function in a non-recursive function that performs these checks once , eg like, 一个不错的解决方案是将函数的递归部分包装在一次执行这些检查的非递归函数中,例如,

     fun power (0, 0) = raise Domain | power (m, n) = if n < 0 then raise Domain else naive_power (m, n) 

    where naive_power was the function above that assumed its input valid. 其中naive_power是假设输入有效的函数。

  5. One other bad thing about this function is that it isn't tail-recursive when it could easily be. 此功能的另一个坏处是,在很容易实现时,它不是尾递归的。 That is, a call to power (m, 5) will evaluate as such: 也就是说,对power (m, 5)的呼吁power (m, 5)将这样评估:

     power (2, 5) ~> 2 * (power (m, 4)) ~> 2 * (2 * (power (m, 3))) ~> 2 * (2 * (2 * (power (m, 2)))) ~> 2 * (2 * (2 * (2 * (power (m, 1))))) ~> 2 * (2 * (2 * (2 * (2 * power (m, 0))))) ~> 2 * (2 * (2 * (2 * (2 * 1)))) ~> 2 * (2 * (2 * (2 * 2))) ~> 2 * (2 * (2 * 4)) ~> 2 * (2 * 8) ~> 2 * 16 ~> 32 

    meaning a lot of function calls waiting for the next function call to resolve before itself can resolve. 意味着很多函数调用等待下一个函数调用解析之后才能解决。 A tail-recursive version might use an additional argument to store the temporary result in and return it at the end: 尾递归版本可能使用附加参数将临时结果存储在其中并在最后将其返回:

     fun power (0, 0) = raise Domain | power (M, N) = let fun power_helper (m, 0, result) = result | power_helper (m, n, tmp) = power_helper (m, n-1, tmp * m) in if N < 0 then raise Domain else power_helper (M, N, 1) end 

    It can be useful to embed helper functions into other functions either because you need to perform certain checks once and have the main, recursive part of your algorithm resolved in another function, or because you wish to add more arguments to your recursive function without breaking the type signature. 将辅助函数嵌入其他函数可能很有用,因为您需要一次执行某些检查并将算法的主要递归部分解析到另一个函数中,或者因为您希望在递归函数中添加更多参数而不会破坏类型签名。 ( power_helper takes three arguments, so a tail-recursive version would not, without being wrapped, be a valid solution to the problem of writing a function with two arguments that calculates mⁿ . power_helper具有三个参数,因此,如果不使用power_helper尾部递归,则尾部递归版本将不是编写具有两个参数的函数来计算mⁿ的问题的有效解决方案。

    Evaluating power (2, 5) assuming its tail-recusive implementation could look as such: 假设其尾部可追溯的实现power (2, 5)评估power (2, 5)如下所示:

     power (2, 5) ~> power_helper (2, 5, 1) ~> power_helper (2, 4, 2) ~> power_helper (2, 3, 4) ~> power_helper (2, 2, 8) ~> power_helper (2, 1, 16) ~> power_helper (2, 0, 32) ~> 32 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM