惯用的 Clojure 中的前一周数和相应年份?

Previous week number and corresponding year in idiomatic Clojure?

我正在学习如何更地道地使用 Clojure。我觉得我的以下实现可以更加地道和简单:

  (defn refine-previous-week-and-year [initial-year, initial-week]
  ;; Returns the week number and year of previous week,
  ;; taking consideration if the current week is 1st week of a year,
  ;; then the previous week is the week 52 of the last year.

  ;; If the initial week number is not nil, keep it as the week number.
  ;; If the initial year number is not nil, keep it as the year number.
  ;; If the intial year is nil, return the current year, unless, the initial-week is nil,
  ;; and the previous week is the week 52 of the last year, then return last year. 
  ;; If the inital week number is nil, then the previous week number is current week minus one,
  ;; unless, the current week 1, then the previous week is 52, and the year is last year.

  (cond
    (and initial-week initial-week) [initial-year initial-week]
    (nil? initial-week) (let [previous-week-raw (- (current-week) 1)]
                          (if (= 0 previous-week-raw)
                            [(if initial-year initial-year (- (current-year) 1)) 52]
                            [(if initial-year initial-year (current-year)) previous-week-raw]))
    (nil? initial-year) [(current-year) initial-week]))

考虑输入参数是否为nil的逻辑比较复杂,考虑前一周是去年的逻辑。

非常感谢您的帮助!

编辑

根据意见和建议,这是我的改进版本:

  (defn refined-previous-week-and-year
    "
    Returns the week number and year of previous week,
    taking consideration if the previous week is the last week
    (52) of the last year.

    If the raw-week number is not nil, keep it as the week number.
    If the raw-year number is not nil, keep it as the year number.

    If the raw-year is nil, return the current year,
    unless the raw-week is nil, and the previous week is the last week (52)
    of the last year, then return last year.

    If the raw-week number is nil,
    then the previous week number is current week minus one,
    unless the previous week is the last week (52) of the last year,
    and the year should be last year.
    "

    [raw-year, raw-week]

    (let [real-year-and-previous-week (memoize  (fn [] (let [previous-week-computed (dec (current-week))
                                                             year (current-year)]
                                                         (if (= 0 previous-week-computed)
                                                           {:year (dec year) :week 52}
                                                           {:year year :week previous-week-computed}))))
          real-year (fn [] (:year (real-year-and-previous-week)))
          real-previous-week (fn [] (:week (real-year-and-previous-week)))]
      {:year (or raw-year (real-year)) :week (or raw-week (real-previous-week))}))

我正在使用函数和 memoize 来延迟实际年份和实际上一周的计算。请问是否可以通过更简单的方法实现?

用(or x y)表达式,逻辑更简单,我解决了处理原始参数是否为nil的卷积,以及上周的计算,用函数捕获计算。

非常感谢您对我学习的帮助!

您可以应用以下一些规则来使它们更加地道:

  • 使用文档字符串而不是注释
  • 删除函数参数列表中的逗号。逗号在 Clojure 中被视为空格,通常会避免使用。换行符和对齐用于提供清晰度。
  • 将模式 (if x x y) 替换为 (or x y)
  • 将 (- x 1) 替换为 (dec x)

您的代码似乎并不像宣传的那样适用于所有情况,它可以变得更简单,主要是将两个输入值视为需要默认的东西(如果它们不存在)。在那之后,过程总是一样的

(defn refine-previous-week-and-year
  "Returns the week number and year of previous week,
  taking consideration if the current week is 1st week of a year,
  then the previous week is the week 52 of the last year."
  [input-year input-week]
  (let [year (or input-year (current-year))  ; Use current year/week
        week (or input-week (current-week))] ; if none provided
    (if (= 1 week)
      [(dec year) 52]
      [year (dec week)])))

编辑:

看来我没有理解你的要求,但我认为你的评论具有误导性,所以我删除了文档字符串。为了获得我认为您想要的行为,我将其拆分为两个更简单的函数:

(defn previous-week
  [year week]
    (if (= 1 week)
      [(dec year) 52]
      [year (dec week)]))

(defn previous-week-if-no-week
  [input-year input-week]
  (let [year (or input-year (current-year))]
    (if input-week
      [year input-week]
      (previous-week year (current-week)))))