【问题标题】:SML list decomposition issueSML列表分解问题
【发布时间】:2020-07-09 14:33:09
【问题描述】:

我找到了华盛顿大学的旧课程 CSE341:编程语言,并尝试继续学习,以便有朝一日能够解决 Paulson 的 面向工作程序员的 ML。所以我有这个:

fun number_in_month5 (m : int, ms : (int*int*int) list) =
    List.length (List.filter (fn (_,x2,_) => x2 = m) ms)

这给了我一个匹配的三元组列表。我可以在前面扔一个List.length 并得到计数。但是这个呢

fun number_in_month6 (m, (_,d2,_) :: ms) =
    List.length (List.filter (fn (_,x2,_) => x2 = m) ms)

: stdIn:279.36 Warning: calling polyEqual
: stdIn:278.5-279.43 Warning: match nonexhaustive
:           (m,(_,d2,_) :: ms) => ...
:   
: val number_in_month6 = fn : ''a * ('b * ''a * 'c) list -> ('b * ''a * 'c) list

测试有时会给出错误的答案

- number_in_month6  (2,[(2018,2,1),(2018,2,2),(2018,1,3),(2018,2,4)])
val it = 2 : int

为什么这不起作用?但是我没有阅读 ML 错误消息的技能。有人建议不要在函数开始时声明类型——我尝试过但没有成功。然后我发现了这个

fun sumlists [] [] : int list = []
    |   sumlists (n :: ns) (m :: ms) = (n + m) :: sumlists ns ms;

    ;;; ML WARNING - Clauses of function declaration are non-exhaustive
    ;;; CONTEXT  :  fun sumlists
    val sumlists = fn : int list -> int list -> int list

定义留下一个表达式,例如sumlists [1] []; 未定义。

所以我理解非穷举的概念,但我无法理解为什么我的函数是非穷举并给出错误的答案。

【问题讨论】:

    标签: list sml decomposition


    【解决方案1】:
    fun number_in_month6 (m, (_,d2,_) :: ms) =
    List.length (List.filter (fn (_,x2,_) => x2 = m) ms)
    
    : stdIn:279.36 Warning: calling polyEqual
    : stdIn:278.5-279.43 Warning: match nonexhaustive
    :           (m,(_,d2,_) :: ms) => ...
    :   
    : val number_in_month6 = fn : ''a * ('b * ''a * 'c) list -> ('b * ''a * 'c) list
    

    我无法理解为什么我的函数不是详尽的并且给出了错误的答案。

    • 非穷举:存在模式(_,d2,_) :: ms 不匹配的值,即[]。问题似乎是您在 number_in_month6 的输入上进行模式匹配,而实际上您只需要在 List.filter 的谓词函数内执行此操作。

      也许这里的误解是“如果我在参数中没有模式匹配,输入将不是三元组列表,因为我删除了类型注释”。知道 SML 的类型推断功能强大到足以通过使用 List.filterfn (_,month2,_) => ... 推断出 ms 是一个三元组列表可能会很有趣。

    • 错误的答案:结果有时差一个,因为您丢弃了第一个元素 (_,d2,_),然后查看过滤后的列表剩余部分 ms 有多长。

      在您的示例中,第一个日期应该计为正确结果 3 的一部分,但它被丢弃了,其余 3 个日期中的 2 个被正确计算。

    解决这个问题:

    fun number_in_month (month1, dates) =
        List.length (List.filter (fn (_, month2, _) => month1 = month2) dates)
    

    并对此进行测试:

    - number_in_month6 (2,[(2018,2,1),(2018,2,2),(2018,1,3),(2018,2,4)]);
    > val it = 3 : int
    

    几点:给变量起更好的名字可以更容易理解发生了什么。您可能需要考虑使用记录而不是元组。它们基本上是一样的,除了元组有编号的条目和记录有命名的条目,而且记录语法有点复杂。但好处是您不会意外忘记这是美国、欧洲还是 ISO 日期:

    type date = { year : int, month : int, day : int }
    
    fun number_in_month (month1, dates : date list) =
        List.length (List.filter (fn ({ month = month2, ... }) => month1 = month2) dates)
    
    val test_1 = number_in_month (2, [ { year = 2018, month = 2, day = 1 }
                                     , { year = 2018, month = 2, day = 2 }
                                     , { year = 2018, month = 1, day = 3 }
                                     , { year = 2018, month = 2, day = 4 }
                                     ])
    

    不过,记录语法可能有点棘手,所以只要您觉得元组实用,请随时继续使用它们。

    【讨论】:

      猜你喜欢
      • 2019-08-20
      • 1970-01-01
      • 2021-07-24
      • 2019-01-17
      • 2021-12-24
      • 1970-01-01
      • 2019-03-06
      • 1970-01-01
      • 2016-01-01
      相关资源
      最近更新 更多