1

更新:我想用这段代码做的是获取日期列表、年/月/日和给定数字作为月份,并检查给定列表中有多少日期与给定的月份。我所说的 x = x + 1 是 x++,例如在 java、C 或 C# 中。作为我想要x的输出。如果没有匹配,0 并且对于任何匹配 x = x + 1

所以这是我的代码,

fun number_in_month (Dlist : (int * int * int) list, Month : int, x : int) =
   if null Dlist then x
   else if #2 (hd Dlist) = Month then x = x + 1 andalso number_in_month (tl(Dlist), Month, x)
        else number_in_month ((tl(Dlist)), Month, x)

它给了我错误:

Error: types of if branches do not agree [tycon mismatch]
      then branch: int
      else branch: bool
       in expression:
       if null Dlist
       then x
       else if (fn <rule>) (hd <exp>) = Month
            then (x = <exp> + <exp>)
                  andalso (number_in_month (<exp>,<exp>,<exp>))
            else number_in_month (tl <exp>,Month,x)

我真的不明白为什么 sml 正在考虑 bool 类型的 x = x + 1。如果有人能告诉我如何正确地说 x = x + 1 in sml,我会非常高兴。提前非常感谢。

4

1 回答 1

4

在标准 ML 中说x = x + 1,你需要澄清你打算说什么,因为显然x = x + 1意味着你不打算说的东西。它的意思是“比较xx + 1说出它们是否相等”(它们永远不会是任何整数)。

我想你想要实现的是“将 x 更新为其后继者”,如果不使用引用类型,这是不可能的,我不鼓励这种做法,因为它们不是不可变的和功能性的。您通常在功能上更新某些内容的方式是将更新的值传递给最终返回它的函数。(使用函数参数作为累积变量,所以感觉好像是相同的变量在每次递归调用时更新它们的值。)

我建议您做的另一件事是使用模式匹配而不是 if-then-else。例如,如果列表匹配,则您知道该列表为空[]。由于您的计算结果不是布尔值,因此您不能使用“... andalso ...” - 我怀疑您这样做是因为您“想同时做两件事,而且起来像”做某事并且还做其他事情”,但这将是一种误解。您可以这样做(使用 eg;before),但您会丢失结果,因为这些运算符处理副作用并丢弃其操作数之一的主要效果,所以它是不是你现在想要的。

这是我在黑暗中刺伤你的意图,使用模式匹配编写的:

fun number_in_month ([], _, x) = x
  | number_in_month ((one,two,three)::dlist, month, x) =
    if two = month then number_in_month(dlist, month, x+1)
                   else number_in_month(dlist, month, x)

修改:您也可以在没有尾递归的情况下执行此操作

fun number_in_month([], _) = 0
  | number_in_month((_,month1,_)::dlist, month2) =
    if month1 = month2 then 1 + number_in_month(dlist, month2)
                       else number_in_month(dlist, month2)

或者写成不同的:

fun number_in_month([], _) = 0
  | number_in_month((_,month1,_)::dlist, month2) =
    (if month1 = month2 then 1 else 0) + number_in_month(dlist, month2)

或使用列表组合器:

fun counter(n1,n2) = if n1 = n2 then 1 else 0
fun number_in_month(dlist, month2) =
    foldl (fn ((_,month1,_),count) => counter(month1,month2) + count) 0 dlist

或者按照您的要求使用参考,即使我不鼓励这样做:

fun number_in_month (dlist, month2) =
    let val count = ref 0
        fun loop [] = !count (* the value inside the ref-cell *)
          | loop ((_,month1,_)::dlist) =
            if month1 = month2 then (count := !count + 1 ; loop dlist)
                               else loop dlist
    in loop dlist end

如您所见,增加了一些复杂性,因为我希望在函数中创建参考单元,但我无法在每次递归调用时创建一个新的参考单元。因此,我创建了一个递归辅助函数,并让它具有在递归期间更改的参数(它可以只继承month2count从 的父范围number_in_month。当递归结束时(基本情况),我选择在 ref-cell (使用标准 ML 的稍微晦涩的语法进行解引用)。

在掌握功能方法之前,不要养成使用 ref-cells 的习惯。否则,您将重新使用一种使这种习惯变得丑陋的语言进行命令式编码。:)

于 2013-10-12T08:40:50.343 回答