number_in_month exercise (SML list iteration)

两盒软妹~` 提交于 2020-03-02 12:40:21

问题


I need to take a list of dates and a list of months and get a total count of the amount of dates that are in any of the months listed. Thus returning a single integer

I had a previously defined number_in_month function which takes in a list of dates and a single month and returns the amount of dates that fall in that month. It has been tested and works correctly. I use this as the foundation for the latter function. I've traced through the number_in_months function many times and I can't seem to find out whats wrong but it is simply not yielding the right answer

fun number_in_month (datelist : (int*int*int)list, month : int)  = 

let
fun count(x : int , datelist : (int*int*int)list)=
if null (tl datelist)
then x
else if #2(hd datelist) = month
then count(x+1, tl datelist)
else count(x, tl datelist)

in

if #2(hd datelist) = month
then count(1, datelist)
else count(0, datelist)

end
fun number_in_months (datelist : (int*int*int)list, monthlist : (int)list)=
let 
fun count(x : int, monthlist : (int)list)=
if null (tl monthlist)
then x
else count((x + number_in_month(datelist, hd monthlist)), tl monthlist) 

in
count (( number_in_month(datelist, hd monthlist), tl monthlist))
end

回答1:


As you have stated, you just have to use the previous function number_in_month. Remembering that number_in_month takes a list of dates and a single month, and returns the number of matching months in the list of dates. Thus All there is needed to create number_in_months, is to call number_in_month for each element in the new list of months, with the original list of dates to be checked.

Such a solution could look like

fun number_in_months (dates, months) =
    if null months then
      0
    else
      number_in_month(dates, hd months) + number_in_months(dates, tl months)

However when you use pattern matching, you can shorten it down and make it even more readable

fun number_in_months (dates, []) = 0
  | number_in_months (dates, d::ds) =
      number_in_month(dates, d) + number_in_months(dates, ds)

There is absolutely no reason for creating a count function, carrying around a "state". This seems to be your imperative mind, at play :) Take for example this simple function which will sum all element of a list

fun sum [] = 0
  | sum (x::xs) = x + sum xs

or even creating a length function (which is actually similar to your count function)

fun length [] = 0
  | length (x::xs) = 1 + length xs

Instead of repeating a lot of good stuff already mentioned so many times, I encouraging you to go read these questions and their answers.

Update

I also wanted to show you how to format you code in a better way

fun number_in_month (datelist : (int*int*int) list, month : int)  =
    let
      fun count (x : int , datelist : (int*int*int) list) =
          if null (tl datelist)
          then x
          else if #2(hd datelist) = month
            then count (x+1, tl datelist)
            else count (x, tl datelist)
    in
      if #2(hd datelist) = month
      then count (1, datelist)
      else count (0, datelist)
    end


fun number_in_months (datelist : (int*int*int) list, monthlist : int list)=
    let
      fun count (x : int, monthlist : int list)=
          if null (tl monthlist)
          then x
          else count (x + number_in_month(datelist, hd monthlist), tl monthlist)
    in
      count (number_in_month (datelist, hd monthlist), tl monthlist)
    end

How to format nested if's is always a great debate where I'm from. Personally I avoid them, and use cases instead but I guess you will lean about that in the future.

However I also spotted a mistake in your count function. When you test whether your second argument (in both of your count functions) are the empty list with null, you do it on the tail of the argument, which will fail if the argument is in fact the empty list

- null (tl []);

uncaught exception Empty

For example this imput

- number_in_months ([(1,1,1)], [1]);

uncaught exception Empty

Also your logic in number_in_month is wrong, as you are testing for the head of the datelist being equal to month, however your to count in either case uses the whole of datelist instead of its tail. This is seen as the below should not return 2 as a result

- number_in_month([(1,1,1), (2,2,2), (3,3,3)], 1);
val it = 2 : int

This error, is the only thing that is making the number_in_month function not throwing up an exception.




回答2:


The problem with your code is, you are not calculating the last date if it is matching with the month. this code works fine.

fun number_in_month (datelist : (int*int*int) list, month : int)  =
    let
      fun count (x : int , datelist : (int*int*int) list) =
          if null (tl datelist)
          then 
              if #2(hd datelist) <> month
                      then x
                     else x+1
         else if #2(hd datelist) = month
            then count (x+1, tl datelist)
            else count (x, tl datelist)
    in
          count (0, datelist)
    end


来源:https://stackoverflow.com/questions/14470895/number-in-month-exercise-sml-list-iteration

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!