Fork of https://github.com/google/lisp-koans so that I could go through them. THIS CONTAINS ANSWERS.

clos.lsp 6.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. ;; Copyright 2013 Google Inc.
  2. ;;
  3. ;; Licensed under the Apache License, Version 2.0 (the "License");
  4. ;; you may not use this file except in compliance with the License.
  5. ;; You may obtain a copy of the License at
  6. ;;
  7. ;; http://www.apache.org/licenses/LICENSE-2.0
  8. ;;
  9. ;; Unless required by applicable law or agreed to in writing, software
  10. ;; distributed under the License is distributed on an "AS IS" BASIS,
  11. ;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. ;; See the License for the specific language governing permissions and
  13. ;; limitations under the License.
  14. ;; CLOS stands for Common Lisp Object System.
  15. ;; CLOS is common lisps' object oriented framework.
  16. (defclass racecar () (color speed))
  17. (define-test test-defclass
  18. (let ((car-1 (make-instance 'racecar))
  19. (car-2 (make-instance 'racecar)))
  20. (setf (slot-value car-1 'color) :red)
  21. (setf (slot-value car-1 'speed) 220)
  22. (setf (slot-value car-2 'color) :blue)
  23. (setf (slot-value car-2 'speed) 240)
  24. (assert-equal ____ (slot-value car-1 'color))
  25. (assert-equal ____ (slot-value car-2 'speed))))
  26. ;; CLOS provides functionality for creating getters / setters
  27. ;; for defined objects
  28. (defclass spaceship ()
  29. ((color :reader get-color :writer set-color)
  30. (speed :reader get-speed :writer set-speed)))
  31. (define-test test-clos-getters-and-setters
  32. (let ((ship-1 (make-instance 'spaceship)))
  33. (set-color :orange ship-1)
  34. (assert-equal ____ (get-color ship-1))
  35. (set-speed 1000 ship-1)
  36. (assert-equal ____ (get-speed ship-1))))
  37. ;; CLOS also provides functionality to create accessors
  38. ;; to object data.
  39. ;; stores a value, and a counter which tallies accesses, read or write,
  40. ;; to that value
  41. (defclass value-with-access-counter ()
  42. ((value :reader get-value :writer set-value :initform 0)
  43. (access-count :reader how-many-value-queries :initform 0)))
  44. (defmethod get-value ((object value-with-access-counter))
  45. (incf (slot-value object 'access-count))
  46. (slot-value object 'value))
  47. (defmethod set-value (new-value (object value-with-access-counter))
  48. (incf (slot-value object 'access-count))
  49. (setf (slot-value object 'value) new-value))
  50. (define-test test-access-counter
  51. (let ((x (make-instance 'value-with-access-counter)))
  52. ; check that no one has ever looked at the x value yet.
  53. (assert-equal ____ (how-many-value-queries x))
  54. ; check that the default value is zero.
  55. (assert-equal ___ (get-value x))
  56. ; now that we've looked at it, there is a single access.
  57. (assert-equal ___ (how-many-value-queries x))
  58. ; check that we can set and read the value
  59. (set-value 33 x)
  60. (assert-equal 33 (get-value x))
  61. (assert-equal ___ (how-many-value-queries x))))
  62. ; countdowner has a value which goes down every time you look at it
  63. ; and returns "bang" when it hits zero.
  64. (defclass countdowner ()
  65. ((value :initform 4)))
  66. ;; Write the get-value for the countdowner
  67. ;; to satisfy the test-countdowner tests.
  68. ;; you may be interested in the 'decf function.
  69. (defmethod get-value ((object countdowner))
  70. :WRITE-ME)
  71. (define-test test-countdowner
  72. (let ((c (make-instance 'countdowner)))
  73. (assert-equal 3 (get-value c))
  74. (assert-equal 2 (get-value c))
  75. (assert-equal 1 (get-value c))
  76. (assert-equal "bang" (get-value c))
  77. (assert-equal "bang" (get-value c))))
  78. ;; Classes can inherit data and methods from other classes.
  79. ;; Here, the specific CIRCLE class extends the generic SHAPE class
  80. (defclass shape ()
  81. ((kind :reader get-kind :writer set-kind :initform :default-shape-kind)
  82. (pos :reader get-pos :writer set-pos :initform '(0 0))))
  83. (defclass circle (shape)
  84. ((radius :reader get-radius :writer set-radius :initform 0)))
  85. (define-test test-inheritance
  86. (let ((circle-1 (make-instance 'circle))
  87. (shape-1 (make-instance 'shape)))
  88. (assert-equal ____ (type-of shape-1))
  89. (assert-equal ____ (type-of circle-1))
  90. (true-or-false? ____ (typep circle-1 'circle))
  91. (true-or-false? ____ (typep circle-1 'shape))
  92. (set-kind :circle circle-1)
  93. (set-pos '(3 4) circle-1)
  94. (set-radius 5 circle-1)
  95. (assert-equal ____ (get-pos circle-1))
  96. (assert-equal ____ (get-radius circle-1))))
  97. ;; Classes may also inherit from more than one base class.
  98. ;; This is known as multiple inheritance.
  99. ;; Color holds an rgb triplet and a transparency alpha value.
  100. ;; The RGB stands for the amount of red, green, and blue.
  101. ;; the alpha (transparency) value is 0 for completely opaque.
  102. ;; Note that color also has a kind, like shape.
  103. (defclass color ()
  104. ((rgb :reader get-rgb :writer set-rgb :initform '(0 0 0))
  105. (alpha :reader get-alpha :writer set-alpha :initform 0)
  106. (kind :reader get-kind :writer set-kind :initform :default-color-kind)))
  107. ;; The COLORED-CIRCLE class extends both CIRCLE and COLOR.
  108. ;; Of particular interest is which "kind" slot will COLORED-CIRCLE get,
  109. ;; since both CIRCLE and COLOR provide the "kind" slot.
  110. (defclass colored-circle (color circle) ())
  111. (defclass circled-color (circle color) ())
  112. (define-test test-multiple-inheritance
  113. (let ((my-colored-circle (make-instance 'colored-circle))
  114. (my-circled-color (make-instance 'circled-color)))
  115. (assert-equal ____ (get-kind my-colored-circle))
  116. (assert-equal ____ (get-kind my-circled-color))))
  117. (defvar *last-kind-accessor* nil)
  118. (defmethod get-kind ((object shape))
  119. (setf *last-kind-accessor* :shape)
  120. (slot-value object 'kind))
  121. (defmethod get-kind ((object circle))
  122. (setf *last-kind-accessor* :circle)
  123. (slot-value object 'kind))
  124. (defmethod get-kind ((object color))
  125. (setf *last-kind-accessor* :color)
  126. (slot-value object 'kind))
  127. ;; Precedence order is similarly a depth first search for methods.
  128. (define-test test-multiple-inheritance-method-order
  129. (let ((my-colored-circle (make-instance 'colored-circle))
  130. (my-circled-color (make-instance 'circled-color))
  131. (my-shape (make-instance 'shape))
  132. (my-circle (make-instance 'circle))
  133. (my-color (make-instance 'color)))
  134. (get-kind my-shape)
  135. (assert-equal ____ *last-kind-accessor*)
  136. (get-kind my-circle)
  137. (assert-equal ____ *last-kind-accessor*)
  138. (get-kind my-color)
  139. (assert-equal ____ *last-kind-accessor*)
  140. (get-kind my-colored-circle)
  141. (assert-equal ____ *last-kind-accessor*)
  142. (get-kind my-circled-color)
  143. (assert-equal ____ *last-kind-accessor*)))
  144. ;; Todo: consider adding :before and :after method control instructions.