【问题标题】:number_in_month exercise (SML error: operator and operand don't agree when comparing integer in list to an integer)number_in_month 练习(SML 错误:将列表中的整数与整数进行比较时,运算符和操作数不一致)
【发布时间】:2020-02-26 05:41:16
【问题描述】:

我是标准 ML 的新手,不知道为什么会出现这种类型不匹配错误:

fun number_in_month (month : int, dates : int list) =                                            
    if null dates                                                                                
    then 0                                                                                       
    else if (month = (hd (tl (hd dates))))            
    then number_in_month(month, (tl dates)) + 1
    else number_in_month(month, (tl dates))

评估此函数会导致以下错误:

Error: operator and operand don't agree [tycon mismatch]     
 5  operator domain: 'Z list                                                                       
 6  operand:         int                                                                           
 7  in expression:                                                                                 
 8    tl (hd dates)     

但是,在 REPL,如果我执行以下操作:

val x = [[84, 12, 23], [83, 01, 18]]
12 = (hd (tl (hd x)))                    (*  -> val it = true : bool *)

我不确定在这种情况下的类型检查规则是什么,我不明白为什么相同的表达式可以在 REPL 上工作,但当我尝试评估函数中的子表达式时却不行。

【问题讨论】:

    标签: sml typechecking


    【解决方案1】:

    您正在获取列表头部的尾部头部。您的 x(在 REPL 中)是 int list list(整数列表的列表)。但是你的函数定义声明了它 作为int list。用dates: int list list 重新声明number_in_month 应该可以解决 你的问题:

    fun number_in_month (month : int, dates : int list list) =  
       ...
    

    它可以在 REPL 中按预期工作,因为您在定义 x 时没有明确声明它的类型。 SML 推断 x 的类型是 int list list,这就是为什么 (hd (tl (hd x))) 通过类型检查器。

    更新

    (试图在 stackoverflow 失败时添加此权限)

    如果您有兴趣,这里有一些关于如何重写代码的想法 更多 ML 风格:

    首先,您可以使用模式匹配:

    fun number_in_month (month: int, []) = 0
      | number_in_month (month: int, ([y,m,d]::rest)) = 
          if month = m then number_in_month(month, rest) + 1
          else number_in_month(month, rest)
    

    所以number_in_month 需要一个月的元组和日期列表,逻辑上是[]([y,m,d]::rest)。这与您选择表示日期的方式兼容 (作为整数列表),但编译时会出现match nonexhaustive 警告。这是有道理的,因为如果您将dates 作为[[84], [83]] 传递会发生什么?模式匹配方法至少会警告您这一点,但使用 (hd (tl (hd dates))) 这样的代码您会得到 尽管您的程序已成功进行类型检查,但运行时错误。你可以添加另一个 日期具有少于/多于 3 个元素的日期列表的模式匹配,但如果 可能,将日期表示为 3 个整数的 元组 可能更简洁。

     type date = (int * int * int)
    

    那么你可以:

    fun number_in_month (month: int, []: date list) = 0
      | number_in_month (month: int, ((y,m,d)::rest)) = 
          if month = m then number_in_month(month, rest) + 1
          else number_in_month(month, rest)
    

    另外,如果您更愿意重用代码,您可以尝试高阶函数(例如foldr):

    fun number_in_month (month: int, dates: date list) =
      foldl (fn ((_,m,_), c) => if m = month then c+1 else c) 0 dates
    

    或者

    fun number_in_month (month: int, dates: date list) =
      length (List.filter (fn (_,m,_) => m = month) dates)
    

    比你要求的要多,但我希望它有所帮助。

    【讨论】:

    • 谢谢!我想通了,但你打败了我!
    猜你喜欢
    • 2020-06-09
    • 1970-01-01
    • 2018-02-11
    • 1970-01-01
    • 2020-05-19
    • 1970-01-01
    • 1970-01-01
    • 2018-04-28
    • 2018-10-13
    相关资源
    最近更新 更多