number_in_month练习(为什么x = x +1被认为是sml中的布尔值,而x是int以及如何正确地表示x = x +1?)

问题描述 投票:1回答: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考虑使用x = x + 1类型的bool。如果有人能告诉我如何正确地在sml中说x = x + 1,我将非常高兴。预先感谢。

list functional-programming sml ml
1个回答
4
投票

在标准ML中说x = x + 1,您需要弄清您要说的话,因为显然x = x + 1意味着您不想要的东西。它的意思是“比较xx + 1并说它们是否相等”(它们永远不会是任何整数)。

我想您想要实现的是“将x更新为它的后继”,如果不使用引用类型,则是不可能的,我不鼓励这样做,因为它们不是不可变的且不起作用。通常在功能上进行更新的方法是将更新的值传递给最终返回该值的函数。 (将函数参数用作累加变量,因此感觉就像是在每次递归调用时更新其值的变量一样。)

我建议您做的另一件事是使用模式匹配,而不是if-then-else。例如,您知道列表与[]匹配时为空。由于您的计算结果不是布尔值,因此您不能使用“ ... andalso ...”-我怀疑您这样做是因为您“想同时做两件事,并且andalso的气味像是“做某事[[并且也做别的事情”,但这可能是一个误解。您可以这样做(例如使用;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)

Modified:您也可以不执行尾递归操作

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

如您所见,由于希望在函数内创建引用单元,所以增加了一些复杂性,但是我无法在每次递归调用时都创建新的引用单元。因此,我创建了一个递归的帮助器函数,并让其具有在递归过程中更改的参数(它可以仅从month2的父作用域继承countnumber_in_month。当递归结束时(基本情况),我选择返回参考单元中的值(使用标准ML稍微模糊的语法进行解引用)。

在掌握功能方法之前,请不要养成使用参考单元的习惯。否则,您将不得不使用一种使这种习惯变得丑陋的语言进行强制性编码。 :)

© www.soinside.com 2019 - 2024. All rights reserved.