【问题标题】:number_in_month exercise (Why x = x + 1 is considered bool in sml while x is int and how to say x = x + 1 correctly?)number_in_month 练习(为什么 x = x + 1 在 sml 中被认为是 bool 而 x 是 int 以及如何正确地说 x = x + 1?)
【发布时间】:2013-10-20 08:18:13
【问题描述】:

更新:我想用这段代码做的是获取日期列表、年/月/日和给定数字作为月份,并检查给定列表中有多少日期在与给定月份相同的月份。我所说的 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,我会非常高兴。 提前非常感谢。

【问题讨论】:

    标签: list functional-programming sml ml


    【解决方案1】:

    在标准 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)
    

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

    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
    

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

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

    【讨论】:

    • 非常感谢!你确实大部分都发现了我的意思。现在,Dlist 是一个 int * int * int 元组的列表,即年/月/日。 int Month 是给定的月份。我试图找出列表中有多少给定日期与给定整数月份在同一月份。试图用整数 x 计算相似度。所以我希望最新的 X 成为我的输出。
    • 如你所说,我所说的 x = x + 1 实际上是 java 或 C 或 C# 中的 x++ 或 i++。
    • 那么,有什么办法可以按照我的意思去做吗?
    • 我提供了几种方法来做到这一点。也许您正在考虑的就是其中之一。
    猜你喜欢
    • 1970-01-01
    • 2019-08-02
    • 2016-01-16
    • 2010-09-11
    • 2015-07-05
    • 1970-01-01
    • 2020-09-24
    • 1970-01-01
    • 2011-11-20
    相关资源
    最近更新 更多