Sml 如何在定义为数据类型的ML中划分两个数字?

Sml 如何在定义为数据类型的ML中划分两个数字?,sml,ml,Sml,Ml,我试图在SML中编写一个递归函数,它接收两个自然数n1,n2并返回n1 div n2的结果 数据类型natural定义如下: datatype natural = zero | Succ of natural 我想用新的数据类型来编写它,或者换句话说,不是通过将它们转换为常规形式并转换回结果 你知道在这个定义中如何除法吗?你可以从定义减法开始: exception Negative fun sub (a, zero) = a | sub (zero, b) = raise Negativ

我试图在SML中编写一个递归函数,它接收两个自然数n1,n2并返回n1 div n2的结果

数据类型natural定义如下:

datatype natural = zero | Succ of natural
我想用新的数据类型来编写它,或者换句话说,不是通过将它们转换为常规形式并转换回结果


你知道在这个定义中如何除法吗?

你可以从定义减法开始:

exception Negative

fun sub (a, zero) = a
  | sub (zero, b) = raise Negative
  | sub (Succ a, Succ b) = sub (a, b)
从这里开始,简单地计算你可以从n1中减去n2而不变成负值的次数应该很容易。特别是,这个等式应该有助于:

n1 div n2 = 1 + (n1 - n2) div n2

剩下的就交给你了。

你可以从定义减法开始:

exception Negative

fun sub (a, zero) = a
  | sub (zero, b) = raise Negative
  | sub (Succ a, Succ b) = sub (a, b)
从这里开始,简单地计算你可以从n1中减去n2而不变成负值的次数应该很容易。特别是,这个等式应该有助于:

n1 div n2 = 1 + (n1 - n2) div n2

剩下的就交给你了。

与Sam Westrick的定义类似,你可以从n1中减去n2而不变成负数的次数,你也可以用加法进行整数除法,大于使用定义,在n2大于n1之前,你可以将其自身相加的次数

从概念上讲,加法似乎比减法更简单。但是“大于”是一个比确定一个数字何时为负数更昂贵的运算符,因为该案例是由归纳法引起的,因此Sam的建议将更有效

您可以通过以下测试来测试您的解决方案:

fun int2nat 0 = Z
  | int2nat n = S (int2nat (n-1))

fun nat2int Z = 0
  | nat2int (S n) = 1 + nat2int n

fun range (x, y) f = List.tabulate (y - x + 1, fn i => f (i + x))

fun divide_test () =
    let fun showFailure (x, y, expected, actual) =
            Int.toString x ^ " div " ^ Int.toString y ^ " = " ^
            Int.toString expected ^ ", but divide returns " ^
            Int.toString actual
    in List.mapPartial (Option.map showFailure) (
         List.concat (
           range (0, 100) (fn x =>
             range (1, 100) (fn y =>
               let val expected = x div y
                   val actual = nat2int (divide (int2nat x, int2nat y))
               in if expected <> actual
                  then SOME (x, y, expected, actual)
                  else NONE
               end))))
    end

与Sam Westrick的定义类似,你可以从n1中减去n2而不变成负数的次数,你也可以用加法进行整数除法,并且大于使用定义,你可以在n2大于n1之前将其自身相加的次数

从概念上讲,加法似乎比减法更简单。但是“大于”是一个比确定一个数字何时为负数更昂贵的运算符,因为该案例是由归纳法引起的,因此Sam的建议将更有效

您可以通过以下测试来测试您的解决方案:

fun int2nat 0 = Z
  | int2nat n = S (int2nat (n-1))

fun nat2int Z = 0
  | nat2int (S n) = 1 + nat2int n

fun range (x, y) f = List.tabulate (y - x + 1, fn i => f (i + x))

fun divide_test () =
    let fun showFailure (x, y, expected, actual) =
            Int.toString x ^ " div " ^ Int.toString y ^ " = " ^
            Int.toString expected ^ ", but divide returns " ^
            Int.toString actual
    in List.mapPartial (Option.map showFailure) (
         List.concat (
           range (0, 100) (fn x =>
             range (1, 100) (fn y =>
               let val expected = x div y
                   val actual = nat2int (divide (int2nat x, int2nat y))
               in if expected <> actual
                  then SOME (x, y, expected, actual)
                  else NONE
               end))))
    end

非常感谢!在你的帮助下,我能够写下剩下的!非常感谢!在你的帮助下,我能够写下剩下的!