如何通过提供一年两天来获得月份清单?

时间:2013-04-05 11:23:30

标签: sml

我有一个名为month_range的函数,每年需要两天作为输入(例如,65和128,假设年份为365天)并返回一个列表,其中包含该日期的月份数第1天到第2天属于。

列表的大小必须为" day2 - day1 + 1"。

示例:month_range(25,35)应返回:[1,1,1,1,1,1,1,2,2,2,2]

我写了以下代码

fun month_range (day1:int,day2:int) =
    let
      val month_days= [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
      fun what_month(day :int) =
          let
            fun aux(sum :int,  numbers: int list) =
                let
                  val numbers_tail = tl numbers
                in
                  if sum <= (hd numbers)
                  then 1
                  else
                    1 + aux(sum, (hd numbers + hd numbers_tail)
                            :: (tl numbers_tail))
                end
          in
            aux(day, month_days)
          end
    in
      if (day1>day2)
      then []
      else what_month(day1) @ what_month(day1 + 1)@::what_month(day2)
    end

但它给了我以下错误

/tmp/emacs-region5156f3r:21.51-21.54 Error: unbound variable or constructor: @::
/tmp/emacs-region5156f3r:21.12-21.70 Error: operator is not a function [literal]
  operator: int
  in expression:
    (what_month (day1 + 1)) <errorvar>
/tmp/emacs-region5156f3r:21.12-21.70 Error: operator and operand don't agree [literal]
  operator domain: 'Z list * 'Z list
  operand:         int * _
  in expression:
    what_month day1 @ (((what_month <exp>) <errorvar>) what_month) day2

uncaught exception Error
  raised at: ../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
             ../compiler/TopLevel/interact/evalloop.sml:44.55
             ../compiler/TopLevel/interact/evalloop.sml:296.17-296.20

1 个答案:

答案 0 :(得分:2)

首先,您可以从错误消息中看到您正在使用@::,这实际上没有任何意义。

您很可能已将函数what_month用于另一个赋值,因此没有理由将其放在let-expression中。

现在,如果我们简化你的代码

val month_days= [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
fun what_month(day :int) =
    let
      fun aux(sum :int,  numbers: int list) =
          let
            val numbers_tail = tl numbers
          in
            if sum <= (hd numbers)
            then 1
            else
              1 + aux(sum, (hd numbers + hd numbers_tail)::(tl numbers_tail))
          end
    in
      aux(day, month_days)
    end


fun month_range (day1:int,day2:int) =
      if (day1>day2)
      then []
      else what_month(day1)

然后我们会看到它仍然没有输入。这是因为what_month函数的类型是int -> int,但是month_range体内的if-expression返回then分支中的列表,那么你还必须返回一个列表其他分支。我们将解决这个问题。

目前,该函数仅返回day1所属月份的编号(理论上,因为尚未键入)。我们不想返回所有日子的日期1 ... day2 这就是递归的地方。如果我们返回what_month(day1)month_range( day1 + 1, day2)的递归调用连接起来,那么我们最终会建立一个列表

what_month(day1) :: what_month(day1 + 1) :: what_month(day1 + 1 + 1) ...

并且由于您返回空列表,当您达到条件day1 > day2时,递归将为您提供这样的结果

what_month(day1) :: what_month(day1 + 1) :: what_month(day1 + 1 + 1)  :: ...
                 :: what_month(day2) ::[]

结果代码如下所示

fun month_range (day1:int,day2:int) =
    if (day1>day2)
    then []
    else what_month(day1) :: month_range(day1 + 1, day2)

- month_range(25,35);
val it = [1,1,1,1,1,1,1,2,2,2,2] : int list