Альтернатива Common Lisp использованию классов

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

В частности, я создаю приложение, в котором я сохраняю значение времени, представляющее количество секунд, прошедших с базового времени (например, 1 января 2000 г., 00:00:00). Я хочу выполнить операции с этим значением, например преобразовать его из секунд в определенное время или дату или из даты в определенные секунды.

Я сделал это, используя класс, однако это кажется расточительным. В частности, каждый раз, когда я получаю доступ к сохраненному значению в течение прошедших секунд, оно будет похоже на (time-time time), где time-time — это метод доступа для экземпляра времени time.

Есть ли лучший способ спроектировать это, возможно, без классов?


person audrow    schedule 22.08.2016    source источник
comment
Почему бы просто не сохранить его как целое число?   -  person jkiiski    schedule 22.08.2016
comment
Чтобы было ясно, вы не хотите использовать универсальные функции времени которые входят в стандарт?   -  person Joshua Taylor    schedule 23.08.2016
comment
В порядке частоты, что вы с ним делаете? Это конкретное время или вы получаете время, прошедшее с момента вашего смещения?   -  person Sylwester    schedule 23.08.2016
comment
@JoshuaTaylor, я не знал о функциях универсального времени. Это очень похоже на то, что я написал. Спасибо, что указали на это.   -  person audrow    schedule 24.08.2016


Ответы (3)


Если у вас есть класс, который просто обертывает один объект, и этот объект имеет известный тип, вы всегда можете вместо этого просто написать методы для класса этого объекта:

(defmethod time-as-unix-time ((tm integer))
  (- tm (load-time-value (encode-universal-time 0 0 0 1 1 1970 0))))

Например.

Конечно, объектно-ориентированные фанатики бросят вас в яму, полную шипов, если поймают, что вы занимаетесь такими вещами: это, без сомнения, нарушает инкапсуляцию или какое-то другое правило культа.

person Community    schedule 23.08.2016
comment
Могу ли я сделать метод более строгим, чем по типу, без использования классов? - person audrow; 24.08.2016
comment
@audrow Ну, вы используете класс, просто встроенный. Вы можете определить любой тип метода для built-in-class, который вы можете использовать для любого другого класса: вы не можете сделать его подклассом, и у него нет никаких слотов или других атрибутов, кроме тех, которые определены для него стандартом. - person ; 24.08.2016
comment
Понимаю. Спасибо. - person audrow; 24.08.2016

Имена доступа

Вы можете называть средства доступа в CLOS как угодно. Функция доступа может называться seconds:

CL-USER 23 > (defclass mytime ()
               ((seconds :accessor seconds :initarg :seconds)))
#<STANDARD-CLASS MYTIME 422015CDD3>

CL-USER 24 > (let ((mt (make-instance 'mytime :seconds 100)))
               (values (seconds mt)
                       (truncate (seconds mt) 60)))
100
1

Быстрый доступ к слотам с помощью функций доступа

Common Lisp также имеет форму WITH-ACCESSORS. Это позволяет нам использовать символ вместо формы доступа в коде - для определенного объекта CLOS. В следующем примере мы можем использовать secs, и это выглядит как переменная в коде, но Common Lisp позаботится о том, чтобы он действительно вызывал метод доступа seconds. Мы можем написать secs вместо (seconds mt). Таким образом, это помогает сделать прилагаемый код короче. Сравните следующий пример с кодом выше.

CL-USER 25 > (let ((mt (make-instance 'mytime :seconds 200)))
               (with-accessors ((secs seconds))
                   mt
                 (values secs (truncate secs 60))))
200
3

Более короткий доступ к слотам через SLOT-VALUE

CLOS также имеет WITH-SLOTS для доступа к слоту через имена слотов, здесь к слоту с именем seconds экземпляра mytime можно получить доступ через имя secs:

CL-USER 26 > (let ((mt (make-instance 'mytime :seconds 200)))
               (with-slots ((secs seconds))
                   mt
                 (values secs (truncate secs 60))))
200
3
person Rainer Joswig    schedule 23.08.2016

Вы можете попробовать закрыть лексическую область следующим образом:

(let ((time (get-universal-time)))
  (defun set-time(tm)
    (setf time tm))

  (defun get-time()
    time)

  (defun get-time-in-some-other-format()
    ;; calculate return value based on 'time'
    )
)
person Claus Brod    schedule 22.08.2016
comment
Вы, наверное, хотели, чтобы это было let ((time (get-universal-time))) ...)? Это альтернатива, но она также делает так, что у вас есть только один экземпляр временной структуры. Это может быть неудобно... - person Joshua Taylor; 23.08.2016
comment
Извините за опечатку, сейчас исправил. - person Claus Brod; 23.08.2016
comment
Это прекрасно. До этого примера я не понимал, как использовать закрытие лексической области видимости. Спасибо. - person audrow; 24.08.2016