История изменений
Исправление quasimoto, (текущая версия) :
(or a b)
http://en.wikipedia.org/wiki/Tagged_union.
В CL это значит, что суммы нужно заворачивать в структуры:
(defstruct my-variant
(variant nil :type (or number string)))
(defmacro with-my-variant ((var my-variant) for-number for-string)
`(let ((,var (my-variant-variant ,my-variant)))
(etypecase ,var
(number ,for-number)
(string ,for-string))))
(defmethod map-as-number ((my-variant my-variant) fn)
(with-my-variant (var my-variant) (funcall fn var) var))
(defmethod map-as-string ((my-variant my-variant) fn)
(with-my-variant (this my-variant) this (funcall fn this)))
(map-as-number (make-my-variant :variant 123) #'1+) ; => 124
(map-as-number (make-my-variant :variant "123") #'1+) ; => "123"
(map-as-string (make-my-variant :variant 123) #'length) ; => 123
(map-as-string (make-my-variant :variant "123") #'length) ; => 3
Следующим шагом будет написание макроса defunion так, чтобы
(defunion number-or-string number string)
раскрывался в код структуры и обобщённых методов работы с данным вариантом (которые потом может неявно использовать, например, паттерн-матчинг).
ломает всю красивую картину ООП и делает диспетчеризацию по произвольным типам принципиально невозможной
Чем сишный union или boost::variant или std.variant из D ломает ООП? Если говорить про «наследники класса как варианты его типа», то sealed class hierarchy - и тоже ничего не ломает.
Исправление quasimoto, :
(or a b)
http://en.wikipedia.org/wiki/Tagged_union.
В CL это значит, что суммы нужно заворачивать в структуры:
(defstruct my-variant
(variant nil :type (or number string)))
(defmacro with-my-variant ((var my-variant) for-number for-string)
`(let ((,var (my-variant-variant ,my-variant)))
(etypecase ,var
(number ,for-number)
(string ,for-string))))
(defmethod map-as-number ((my-variant my-variant) fn)
(with-my-variant (var my-variant) (funcall fn var) var))
(defmethod map-as-string ((my-variant my-variant) fn)
(with-my-variant (this my-variant) this (funcall fn this)))
(map-as-number (make-my-variant :variant 123) #'1+) ; => 124
(map-as-number (make-my-variant :variant "123") #'1+) ; => "123"
(map-as-string (make-my-variant :variant 123) #'length) ; => 123
(map-as-string (make-my-variant :variant "123") #'length) ; => 3
Следующим шагом будет написание макроса defunion так, чтобы
(defunion number-or-string number string)
раскрывался в код структуры и обобщённых методов работы с данным вариантом (которые потом может неявно использовать, например, паттерн-матчинг).
ломает всю красивую картину ООП и делает диспетчеризацию по произвольным типам принципиально невозможной
Чем сишный union или boost::variant или std.variant из D ломает ООП? Если говорить про «наследники класса как варианты его типа», то sealed/final для базового класса - и тоже ничего не ломает.
Исходная версия quasimoto, :
(or a b)
http://en.wikipedia.org/wiki/Tagged_union.
В CL это значит, что суммы нужно заворачивать в структуры:
(defstruct my-variant
(variant nil :type (or number string)))
(defmacro with-my-variant ((var my-variant) for-number for-string)
`(let ((,var (my-variant-variant ,my-variant)))
(etypecase ,var
(number ,for-number)
(string ,for-string))))
(defmethod map-as-number ((my-variant my-variant) fn)
(with-my-variant (var my-variant) (funcall fn var) var))
(defmethod map-as-string ((my-variant my-variant) fn)
(with-my-variant (this my-variant) this (funcall fn this)))
(map-as-number (make-my-variant :variant 123) #'1+) ; => 124
(map-as-number (make-my-variant :variant "123") #'1+) ; => "123"
(map-as-string (make-my-variant :variant 123) #'1+) ; => 123
(map-as-string (make-my-variant :variant "123") #'length) ; => 3
Следующим шагом будет написание макроса defunion так, чтобы
(defunion number-or-string number string)
раскрывался в код структуры и обобщённых методов работы с данным вариантом (которые потом может неявно использовать, например, паттерн-матчинг).
ломает всю красивую картину ООП и делает диспетчеризацию по произвольным типам принципиально невозможной
Чем сишный union или boost::variant или std.variant из D ломает ООП? Если говорить про «наследники класса как варианты его типа», то sealed/final для базового класса - и тоже ничего не ломают.