【问题标题】:How to make a multiplication function using just addition function and iterate function in SML如何在 SML 中仅使用加法函数和迭代函数来制作乘法函数
【发布时间】:2020-12-17 02:20:45
【问题描述】:

我在 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。

任何帮助将不胜感激!

【问题讨论】:

    标签: sml smlnj


    【解决方案1】:

    所以诀窍是使用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)
    

    现在,这当然是非常低效且完全没有必要的,因为我们已经有了 +,但是为了演示数字递归,这是一个如何使用 multiplypower 进行改进的示例(仍在假设我们还没有iterate)。

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

    你可以用非常相似的方式写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)。

    (这个multiply不是尾递归的,因为最外层的表达式(x + ...~x + ...)不是对multiply的调用(因为调用发生在+的操作数内). 这对你来说可能不是问题,但如果是,你不能轻易写... then multiply (x + ...) (y - 1),因为当我们使用x 来累积结果时,任何后续的递归调用都增加了x ,这意味着我们不能再将x 添加到...本身...因为x 现在意味着两件事:累积结果,以及每次递归调用需要添加一次的内容。) p>

    无论如何,要完成最后一步,您必须确定iterate 与我制作的addmultiply 的共同点。当您可以发现共同点时,您可以将其隔离并调用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”,这是错误的解释。这个函数在then 下实际上说的是“使用三个参数调用iteraten-1ff x;因为n-1 的绑定不如函数应用程序紧密,而f x 函数应用程序(它是左关联的),我们在它们周围添加括号;这对于f 不是必需的。”

    addmultiply 中,y 被用作计数变量,而在iterate 中它是n。所以名称和位置发生了变化,这意味着基于iteratemultiply 必须将xy 放在正确的位置。至于确定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"
    

    由于整数没有很好的解决方案,你要么必须切换到real类型来表达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
    

    内部函数go看起来非常像上面的add,除了x变成了result1变成了add+变成了*,还有没有否定案例 (if y &gt; 0 ... else ...)。

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

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

    (...全部以iterate 表示;在power 函数及其范围内的参数的上下文中,它们可能被称为其他名称。)

    【讨论】:

    • 非常感谢!我是 SML 的新人,而且我的语法很混乱。
    猜你喜欢
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 2012-12-25
    • 2020-12-17
    • 2015-12-31
    • 2016-01-18
    • 2021-06-01
    • 1970-01-01
    相关资源
    最近更新 更多