如何在SML中仅使用加法函数和迭代函数来制作乘法函数

问题描述

在SML中,我有两个功能,additerate

fun add(x,y) = x + y

fun iterate n f x = if n > 0 then iterate (n-1) f(f x) else x;

仅使用这两个函数,如何编写一个multiply函数,例如如果键入:

multiply 5 6

返回30。

然后在此基础上,我需要一个名为power的函数,该函数仅使用iteratemultiply将第一个参数提高为第二个参数的幂。一个例子:

power 5 4

它应该返回625。

任何帮助将不胜感激!

解决方法

因此,诀窍是使用iterate来帮助您递归应用add。由于iterate是一个将函数作为参数的列表组合器,因此,如果您以非常简单的方式进行操作,可能会更简单:例如,您可以通过递归地递增或递减来定义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)

现在,由于我们已经有了+,所以这当然是非常低效的,而且完全没有必要,但是为了演示数字的递归,这是如何使用multiply和{{ 1}}(仍然假设我们还没有power)。

此处的一般方法是递归:由于该函数采用两个操作数,因此将一个用作“累加结果”,将另一个用作“计数变量”。因为这是一个简单的问题,所以您仅可以将iteratex用作函数任务的完整环境。在稍大的问题中,您可能会引入更多作为临时/中间结果的参数。

您可以用非常相似的方式写y

multiply

此功能解决了任务(尽管仍然没有fun multiply x 0 = 0 | multiply x y = if y > 0 then x + multiply x (y-1) else ~x + multiply x (y+1) )。

iterate不是尾部递归的,因为最外面的表达式(multiplyx + ...)不是对~x + ...的调用(因为调用发生在multiply的操作数之内,这对您来说可能不是问题,但如果是这样,您就很难编写+,因为当我们使用... then multiply (x + ...) (y - 1)时在累加结果方面,任何后续递归调用都增加了x,这意味着我们不能再将x添加到...本身...,因为x现在意味着两件事:累加结果,并且每个递归调用都需要添加一次。)

无论如何,要走到最后一步,您必须确定x与我所做的iterateadd的共同点。当您可以找到公分母时,可以将其隔离,然后调用multiply。我想修复一个空格“ bug”,它可能会使您对iterate的解释感到困惑:

iterate

添加此空间不会改变函数的行为,但是在阅读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下表示的是“用三个参数调用theniteraten-1f;因为f x的绑定不太紧密而不是函数应用程序,而n-1是函数应用程序(它是左关联的),我们在它们周围加上括号;对于f x而言,这不是必需的。”

fadd中,multiply被用作计数变量,而在y中,它是iterate。因此名称和位置已更改,这意味着基于n的{​​{1}}必须将multiplyiterate放置在正确的位置。至于确定x的值:将y添加到其结果中的函数呢?您可以使用lambda f或部分使用功能x来表达此功能。

最后,对于(fn z => ...),这是几乎相同的问题:

add

由于没有很好的整数解决方案,您必须切换为 real 类型来表示 1 / x ^ n ,也可以翻转条件并在开始递归之前将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"

内部函数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 ,除了go变成了addx变成了result,并且1已成为add,并且没有否定情况(+)。

因此,这意味着您可以实际使用*代替if y > 0 ... else ...,只要您为iterate找到良好的价值:

  • go应该是什么? (有点倒计时)。
  • iterate n f x应该是什么? (执行逐步计算的内容。)
  • n应该是什么? (在逐步计算中应用的内容。)

(...全部用f表示;在x函数及其作用域内的参数的上下文中,它们可能被称为其他名称。)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...