Почему Emacs жалуется на год-переменную void в моем файле.emacs?

Я пытаюсь реализовать солнечные термины в моем .emacs так что мои "праздники" будут отображать время, когда солнечная долгота пересекает каждый кратный 15 градусов. Вот соответствующий фрагмент.

(defun next-solar-term-date (d)
  (solar-date-next-longitude d 15))

(defconst solar-term-names
  ["moderate cold" "severe cold" "spring commerces"
   "rain water" "insects awaken" "vernal equinox"
   "Ching Ming" "corn rain" "summer commerces"
   "corn forms" "corn on ear" "summer solstice"
   "minor heat" "great heat" "autumn commerces"
   "end of heat" "white dew" "autumnal equinox"
   "cold dew" "frost" "winter commerces"
   "light snow" "heavy snow" "winter solstice"])

(setq solar-terms-holidays
      (let* ((k 0) (mylist nil))
        (dotimes (k 4);k=season
          (let* ((j 0))
            (dotimes (j 5);no equinoxes/solstices --- use solar for them
              (let* ((i (+ j (* 6 k)))
                     (month (+ 1 (/ i 2)))
                     (astronextdate (next-solar-term-date
                                     (calendar-astro-from-absolute
                                      (+ (* 15 i)
                                         (calendar-absolute-from-gregorian
                                          (list 1 1 displayed-year))))))
                     (s (aref solar-term-names i))
                     (absnextdate (calendar-absolute-from-astro
                                   astronextdate))
                     (gregnextdate (calendar-gregorian-from-absolute
                                    (floor absnextdate)))
                     (compt (* 24 (- absnextdate (floor absnextdate))))
                     (str (concat s " "
                                  (solar-time-string
                                   compt (if (dst-in-effect absnextdate)
                                             calendar-daylight-time-zone-name
                                           calendar-standard-time-zone-name))))
                     (d (extract-calendar-day gregnextdate)))
                (setq mylist (append mylist
                                     (list
                                      (list 'holiday-fixed month d str))))))))
        mylist))

Однако emacs (версия 23.2-r2 в Gentoo) жалуется на то, что отображаемый год является переменной-пустотой при запуске, и попытка сгенерировать календарь с помощью Mx calendar RET также не помогает. Есть идеи, как я могу это исправить? (Конечно, не с указанием отображаемого года в моем .emacs так как это определенно испортит все остальное...)

2 ответа

Решение

Расчет должен быть отложен до displayed-year доступен, что может быть достигнуто путем замены последнего выражения в вашей вставке на эти два:

(defun solar-term (i month)
  (let* ((astronextdate (next-solar-term-date
                         (calendar-astro-from-absolute
                          (+ (* 15 i)
                             (calendar-absolute-from-gregorian
                              (list 1 1 displayed-year))))))
         (s (aref solar-term-names i))
         (absnextdate (calendar-absolute-from-astro
                       astronextdate))
         (gregnextdate (calendar-gregorian-from-absolute
                        (floor absnextdate)))
         (compt (* 24 (- absnextdate (floor absnextdate))))
         (str (concat s " "
                      (solar-time-string
                       compt (if (dst-in-effect absnextdate)
                                 calendar-daylight-time-zone-name
                               calendar-standard-time-zone-name))))
         (d (extract-calendar-day gregnextdate)))
    (holiday-fixed month d str)))

(setq solar-terms-holidays
      (let* ((mylist nil))
        (dotimes (k 4)    ;k=season
          (dotimes (j 5)  ;no equinoxes/solstices --- use solar for them
            (let* ((i (+ j (* 6 k)))
                   (month (+ 1 (/ i 2))))
              (push `(solar-term ,i ,month) mylist))))
        mylist))

Потому что вы не связали символ displayed-year к стоимости. Проверьте последнюю строку в let* привязка для astronextdate:

                                      (list 1 1 displayed-year))))))

Этот символ не привязан ни к какому значению, поэтому вы получаете ошибку переменной void. Переменная определяется в calendar библиотека, которая имеет документацию:

;; A note on free variables:

;; The calendar passes around a few dynamically bound variables, which
;; unfortunately have rather common names.  They are meant to be
;; available for external functions, so the names can't be changed.

;; displayed-month, displayed-year: bound in calendar-generate, the
;;   central month of the 3 month calendar window

Итак, похоже, вам просто нужно добавить:

(require 'calendar)

заставить Emacs загрузить пакет, который определяет переменную перед этим.

Тем не менее, это будет определено, но еще не связано. Вы должны изменить свой код, чтобы не принимать статически связанные solar-terms-holidays, но должен превратить его в функцию, которая вычисляет их по требованию, потому что displayed-year привязан только когда календарь на самом деле работает...

Итак, одно из возможных решений заключается в следующем: setq чтобы убедиться, что переменные связаны так, как вы ожидаете, будут:

(save-window-excursion
  (calendar)
  (setq solar-terms-holidays
        ....)
  (calendar-exit))
Другие вопросы по тегам