如何在SML中使用加法函数和迭代函数生成乘法函数

如何在SML中使用加法函数和迭代函数生成乘法函数,sml,smlnj,Sml,Smlnj,我在SML中有两个函数,add和iterate fun add(x,y)=x+y fun iterate n f x=如果n>0,则迭代(n-1)f(f x)else x; 仅使用这两个函数,如何编写乘法函数,例如,如果键入: multiply 5 6 返回30 在此基础上,我需要一个名为power的函数,它只使用iterate和multiply将第一个参数提升为第二个参数的幂。例如: power 5 4 它应该返回625 任何帮助都将不胜感激 所以诀窍是使用迭代来帮助您递归地应用添加。由

我在SML中有两个函数,
add
iterate

fun add(x,y)=x+y
fun iterate n f x=如果n>0,则迭代(n-1)f(f x)else x;
仅使用这两个函数,如何编写
乘法
函数,例如,如果键入:

multiply 5 6
返回30

在此基础上,我需要一个名为
power
的函数,它只使用
iterate
multiply
将第一个参数提升为第二个参数的幂。例如:

power 5 4
它应该返回625


任何帮助都将不胜感激

所以诀窍是使用
迭代
来帮助您递归地应用
添加
。由于
iterate
是一个以函数为参数的列表组合器,如果您以非常简单的方式进行操作,可能会更简单:例如,您可以通过递归递增/递减1来定义
add

(* Written using if-then-else *)
fun add x y =
    if y = 0 then x else
    if y > 0 then add (x+1) (y-1) else add (x-1) (y+1)

(* Written using mixture of pattern-matching and if-then-else *)
fun add x 0 = x
  | add x y = if y > 0
              then add (x+1) (y-1)
              else add (x-1) (y+1)
现在,这当然是非常低效和完全没有必要的,因为我们已经有了
+
,但是为了演示数字的递归,这是一个如何使用
乘法和
的例子(仍然假设我们还没有
迭代

这里的一般方法是递归:因为函数需要两个操作数,所以使用一个作为“累加结果”,另一个作为“计数变量”。因为这是一个简单的问题,所以您可以使用
x
y
作为函数任务的完整环境。在稍微大一点的问题中,您可能会引入更多作为临时/中间结果的参数

您可以用非常类似的方式编写
乘法

fun multiply x 0 = 0
  | multiply x y = if y > 0
                   then  x + multiply x (y-1)
                   else ~x + multiply x (y+1)
此函数用于解决任务(尽管仍然没有迭代)

(这个
乘法
不是尾部递归的,因为最外层的表达式(
x+…
~x+…
)不是对
乘法
的调用(因为调用发生在
+
的操作数内部)。这对您来说可能不是问题,但如果是,您就无法轻松编写
…然后乘法(x+…)(y-1)
,因为当我们使用
x
来累加结果时,任何后续递归调用都会增加
x
,这意味着我们不能再将
x
添加到…本身…因为
x
现在意味着两件事:累加结果和每次递归调用需要添加一次的内容。)

无论如何,要完成最后一步,您必须确定
iterate
与我制作的
add
multiply
有什么共同之处。当您能够发现公共分母时,您可以将其隔离并调用
iterate
。我想修复一个可能会混淆您对
迭代的解释的空白“bug”:

fun iterate n f x = if n > 0
                    then iterate (n-1) f (f x)
                    else x;          (* ^- this space! *)
添加此空格不会改变函数的行为,但是当读取
f(f x)
时,人们会倾向于相信它说“将
f
应用到
f x
”,这是错误的解释。在
下,这个函数实际上说的是“调用
迭代
,有三个参数:
n-1
f
fx
;因为
n-1
绑定比函数应用程序更紧密,
fx
是函数应用程序(左关联),我们在其周围添加括号;这对于
f
不是必需的

add
multiply
中,
y
被用作计数变量,而在
iterate
中则是
n
。因此名称和位置发生了变化,这意味着基于
iterate
multiply
必须将
x
y
放在正确的位置。至于确定
f
的值:将
x
添加到其结果中的函数如何?您可以使用lambda、
(fn z=>…)
来表示此函数,也可以使用函数的部分应用程序
add

最后,使用
power
时,问题大致相同:

fun power x 0 = 1
  | power x n = if n > 0
                then x * power x (n-1)
                else raise Fail "Cannot express 1/x^n as integer"
由于整数没有一个好的解决方案,您必须切换到实数类型以表示1/x^n,也可以在开始递归之前翻转条件并从图片中获取
n<0
的情况:

fun power x n =
    if n < 0 then raise Fail "Cannot express 1/x^n as integer"
    else let fun go result 0 = result
               | go result i = go (result * x) (i-1)
         in go 1 n
         end
fun power x n=
如果n<0,则raise Fail“无法将1/x^n表示为整数”
否则让乐趣消失结果0=结果
|通过结果i=通过(结果*x)(i-1)
围棋1N
结束
内部函数
go
看起来非常像上面的
add
,除了
x
变成了
result
1
变成了
add
+
变成了
*
,没有否定的情况(
如果y>0…否则…

因此,这意味着您实际上可以使用
iterate
而不是
go
,只要您为
iterate n f x
找到好的值:

  • n
    应该是什么?(倒计时。)
  • f
    应该是什么?(执行逐步计算的东西。)
  • x
    应该是什么?(逐步计算中应用的内容。)

(…所有的
迭代
;在
power
函数及其作用域中的参数的上下文中,它们可能被称为其他名称。)

非常感谢!我是SML的新员工,在语法上我是个铁杆。