SML列表分解问题
SML list decomposition issue
我找到了华盛顿大学的旧课程 CSE341:编程语言 并且正在努力跟进,这样我就有朝一日可以解决 Paulson 的 ML for the Working程序员。所以我有这个:
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
The definition leaves an expression such as sumlists [1] [];
undefined.
所以我理解非穷尽的概念,但我无法理解为什么我的函数是非穷尽的并且给出了错误的答案。
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
I can't fathom why my function is non-exhaustive and giving bad answers.
非穷举:存在模式 (_,d2,_) :: ms
无法匹配的值,即 []
。问题似乎是,当您实际上只需要在 List.filter
.
的谓词函数内执行此操作时,您根本无法对 number_in_month6
的输入进行模式匹配
也许这里的误解是“如果我不在参数中进行模式匹配,输入将不会是三元组列表,因为我删除了类型注释”。知道 SML 的类型推断足够强大,仅通过使用 List.filter
和 fn (_,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 }
])
不过,记录语法可能有点棘手,所以只要您觉得元组实用,请随时继续使用它们。
我找到了华盛顿大学的旧课程 CSE341:编程语言 并且正在努力跟进,这样我就有朝一日可以解决 Paulson 的 ML for the Working程序员。所以我有这个:
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
The definition leaves an expression such as
sumlists [1] [];
undefined.
所以我理解非穷尽的概念,但我无法理解为什么我的函数是非穷尽的并且给出了错误的答案。
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
I can't fathom why my function is non-exhaustive and giving bad answers.
非穷举:存在模式
的谓词函数内执行此操作时,您根本无法对(_,d2,_) :: ms
无法匹配的值,即[]
。问题似乎是,当您实际上只需要在List.filter
.number_in_month6
的输入进行模式匹配也许这里的误解是“如果我不在参数中进行模式匹配,输入将不会是三元组列表,因为我删除了类型注释”。知道 SML 的类型推断足够强大,仅通过使用
就可以推断出List.filter
和fn (_,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 }
])
不过,记录语法可能有点棘手,所以只要您觉得元组实用,请随时继续使用它们。