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

时间:2017-12-27 14:41:25

标签: sml ml

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

数据类型natural定义如下:

datatype natural = zero | Succ of natural

我想用新数据类型来编写它,换句话说,不是将它们转换为常规形式并转换回结果。

有关如何在此定义中进行分割的想法吗?

2 个答案:

答案 0 :(得分:3)

您可以从定义减法开始:

exception Negative

fun sub (a, zero) = a
  | sub (zero, b) = raise Negative
  | sub (Succ a, Succ b) = sub (a, b)

从这里开始,只需计算从n2减去n1而不消极的次数应该很容易。特别是,这个等式应该有所帮助:

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

我会把剩下的留给你。

答案 1 :(得分:0)

类似于Sam Westrick的定义,“你可以从n2中减去n1而不会消极”的次数,你也可以使用加法进行整数除法,并使用大于定义的整数除法,“数字有时您可以在n2之前将n1添加到自身。

datatype nat = Z | S of nat

fun gt (S x, S y) = gt (x, y)
  | gt (S _, Z) = true
  | gt (Z, _) = false

fun add (x, Z) = x
  | add (x, S y) = add (S x, y)

fun divide (_, Z) = raise Domain
  | divide (x, y) = (* ... *)

添加可能看起来比减法在概念上更简单。但是比确定一个数字是否为负值更大的运营商,因为案件是由感应引起的,所以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