Recursion SML中的尾部递归不显示任何输出

Recursion SML中的尾部递归不显示任何输出,recursion,programming-languages,functional-programming,sml,smlnj,Recursion,Programming Languages,Functional Programming,Sml,Smlnj,在我上一篇文章之后,我尝试执行建议并转换代码 使用let将其转换为尾部递归方法 无法工作的原始代码-(由于在if条件中使用val): 我得到: uncaught exception Bind [nonexhaustive binding failure] raised at: stdIn:216.13-216.50 我知道代码很难阅读,而且很长,但是我非常感激 如果有人可以向我解释如何修复它,或者帮助我找到输出的原因 谢谢您的代码有一些问题 首先,您可以使用last获取列表的最后一个元素。

在我上一篇文章之后,我尝试执行建议并转换代码 使用
let
将其转换为尾部递归方法

无法工作的原始代码-(由于在
if
条件中使用
val
):

我得到:

uncaught exception Bind [nonexhaustive binding failure]
  raised at: stdIn:216.13-216.50
我知道代码很难阅读,而且很长,但是我非常感激 如果有人可以向我解释如何修复它,或者帮助我找到输出的原因


谢谢

您的代码有一些问题

首先,您可以使用
last
获取列表的最后一个元素。有关更多信息,请参阅。但是,除非你有很好的理由这样做,否则从列表的开头开始,并在递归时从开头弹出元素,会更容易、更有效。您已经使用模式匹配将第一个元素绑定到代码中的
head

其次,除非您使用
ref
s(您可能不想这样做),否则标准ML中没有变量,只有值。这意味着,如果希望在调用之间传递状态,则任何累加器都必须是函数的参数。使用辅助函数初始化累加器是一种常见模式

第三,使用
null
函数来测试列表是否为空,而不是将列表与
[]
进行比较。相信我。由于微妙的类型推断问题,您将使用
=
获得警告。更好的方法是对函数的参数使用模式匹配,或者使用
case
语句。模式匹配允许编译器告诉您是否已经处理了所有可能的情况

第四,SML通常使用camelCase而不是snake_case作为变量名。这更具风格,但随着您编写更多代码和协作,您将希望符合约定

第五,当您对列表执行递归时,不要尝试查看列表中的多个值。这使事情复杂化。将它视为一个head元素和tail列表,一切都会变得简单得多。在我的代码中,我没有在列表中保持当前状态,而是将其拆分为一个单独的参数。有一个基本情况,您只需从一个累加器返回答案,还有一个递归情况,您使用更新的累加器值和从列表中弹出的单个值进行递归。这消除了问题场景

我不确定这个逻辑是否正确,因为我不知道您试图计算的是什么,但是请查看这段代码,它演示了我所讨论的一些事情

(* This is the helper function which takes accumulators as
   parameters. You shouldn't call this directly. *)
fun calc' decimal _ _ _ _ [] =
    (* We processed everything in the list.  Just return the accumulator. *)
    decimal
  | calc' decimal multiple lastAdd lastSub current (top::tail) =
    (* This case is for when there are 1 or more elements in the list. *)
    if current > top then
        calc' (decimal + current - top) multiple lastAdd top top tail
    else if current = top then
        calc' (decimal + current) (multiple + 1) lastAdd lastSub top tail
    else
        calc' (decimal + current) 0 current lastSub top tail

(* This is the function you should call. *)
fun calc [] = 0
  | calc [_] = 0 (* Given a single-element list. *)
  | calc (x::xs) =
    (* Apply the helper with correct initial values. *)
    calc' 0 0 0 0 x xs
在函数式语言中,在需要更改变量时,只需递归并为正确的参数指定新值,而不是将其赋值。这就是如何使用递归在函数语言中编写“循环”。只要您只使用尾部递归,它就和您最喜欢的命令式语言中的while循环一样高效

calc([0,100,20,30,4,50]);
uncaught exception Bind [nonexhaustive binding failure]
  raised at: stdIn:216.13-216.50
(* This is the helper function which takes accumulators as
   parameters. You shouldn't call this directly. *)
fun calc' decimal _ _ _ _ [] =
    (* We processed everything in the list.  Just return the accumulator. *)
    decimal
  | calc' decimal multiple lastAdd lastSub current (top::tail) =
    (* This case is for when there are 1 or more elements in the list. *)
    if current > top then
        calc' (decimal + current - top) multiple lastAdd top top tail
    else if current = top then
        calc' (decimal + current) (multiple + 1) lastAdd lastSub top tail
    else
        calc' (decimal + current) 0 current lastSub top tail

(* This is the function you should call. *)
fun calc [] = 0
  | calc [_] = 0 (* Given a single-element list. *)
  | calc (x::xs) =
    (* Apply the helper with correct initial values. *)
    calc' 0 0 0 0 x xs