summaryrefslogtreecommitdiffhomepage
path: root/ms-my/common-lisp-my.html.markdown
blob: f5914aae3839164eab70c06e461c19fcd212485e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
---

language: "Common Lisp"
filename: commonlisp-ms.lisp
contributors:
  - ["Paul Nathan", "https://github.com/pnathan"]
  - ["Rommel Martinez", "https://ebzzry.io"]
translators:
  - ["Burhanuddin Baharuddin", "https://github.com/burhanloey"]
lang: ms-my
---

Common Lisp ialah programming language yang general-purpose (boleh digunakan untuk semua benda) dan multi-paradigm (konsep yang pelbagai) sesuai untuk pelbagai kegunaan di dalam
industri aplikasi. Common Lisp biasa digelar sebagai programmable programming language (programming language yang boleh di-program-kan).

Sumber bacaan yang klasik ialah [Practical Common Lisp](http://www.gigamonkeys.com/book/). Sumber bacaan yang lain dan
yang terbaru ialah [Land of Lisp](http://landoflisp.com/). Buku baru mengenai best practices (amalan terbaik),
[Common Lisp Recipes](http://weitz.de/cl-recipes/), baru sahaja diterbitkan.



```common-lisp

;;;-----------------------------------------------------------------------------
;;; 0. Syntax
;;;-----------------------------------------------------------------------------

;;; General form (Bentuk umum)

;;; Ada dua asas dalam syntax CL: ATOM dan S-EXPRESSION.
;;; Kebiasaannya, gabungan S-expression dipanggil sebagai `forms`.

10            ; atom; bermaksud seperti yang ditulis iaitu nombor 10
:thing        ; juga atom; bermaksud simbol :thing
t             ; juga atom, bermaksud true (ya/betul/benar)
(+ 1 2 3 4)   ; s-expression
'(4 :foo t)   ; juga s-expression


;;; Comment (Komen)

;;; Comment satu baris bermula dengan semicolon; gunakan empat untuk comment
;;; mengenai file, tiga untuk seksyen penghuraian, dua untuk yang dalam definition,
;;; dan satu untuk satu baris. Sebagai contoh,

;;;; life.lisp

;;; Foo bar baz, disebabkan quu quux. Sangat optimum untuk krakaboom dan umph.
;;; Diperlukan oleh function LINULUKO. Ini merepek sahaja kebaboom.

(defun meaning (life)
  "Memulangkan hasil pengiraan makna KEHIDUPAN"
  (let ((meh "abc"))
    ;; Jalankan krakaboom
    (loop :for x :across meh
       :collect x)))                    ; Simpan hasil ke x, kemudian pulangkan

;;; Komen berbentuk blok, sebaliknya, membenarkan komen untuk bentuk bebas. Komen
;;; tersebut berada di antara #| dan |#

#| Ini adalah komen berbentuk blok di mana
   tulisan boleh ditulis dalam beberapa baris dan
    #|
       juga boleh dalam bentuk nested (berlapis-lapis)!
    |#
|#


;;; Environment (benda-benda yang diperlukan untuk program menggunakan Common Lisp)

;;; Common Lisp ada banyak jenis; kebanyakannya mengikut standard. SBCL
;;; ialah titik permulaan yang baik. Quicklisp boleh digunakan untuk install 
;;; library third party.

;;; CL kebiasaannya digunakan dengan text editor dan Real Eval Print
;;; Loop (REPL) yang dilancarkan dengan serentak. REPL membolehkan kita menjelajah
;;; program secara interaktif semasa program tersebut sedang berjalan secara "live".


;;;-----------------------------------------------------------------------------
;;; 1. Datatype primitif dan operator
;;;-----------------------------------------------------------------------------

;;; Simbol

'foo ; => FOO  Perhatikan simbol menjadi huruf besar secara automatik.

;;; INTERN menjadikan string sebagai simbol secara manual.

(intern "AAAA")        ; => AAAA
(intern "aaa")         ; => |aaa|

;;; Nombor

9999999999999999999999 ; integer
#b111                  ; binary => 7
#o111                  ; octal => 73
#x111                  ; hexadecimal => 273
3.14159s0              ; single
3.14159d0              ; double
1/2                    ; ratio
#C(1 2)                ; complex number

;;; Function ditulis sebagai (f x y z ...) di mana f ialah function dan
;;; x, y, z, ... adalah argument.

(+ 1 2)                ; => 3

;;; Jika anda ingin membuat data sebagai data bukannya function, gunakan QUOTE
;;; untuk mengelakkan data tersebut daripada dikira oleh program

(quote (+ 1 2))        ; => (+ 1 2)
(quote a)              ; => A

;;; Singkatan untuk QUOTE ialah ' (tanda petikan)

'(+ 1 2)               ; => (+ 1 2)
'a                     ; => A

;;; Operasi arithmetic asas

(+ 1 1)                ; => 2
(- 8 1)                ; => 7
(* 10 2)               ; => 20
(expt 2 3)             ; => 8
(mod 5 2)              ; => 1
(/ 35 5)               ; => 7
(/ 1 3)                ; => 1/3
(+ #C(1 2) #C(6 -4))   ; => #C(7 -2)

;;; Boolean

t                      ; true; semua nilai yang bukan NIL ialah true
nil                    ; false; termasuklah list yang kosong: ()
(not nil)              ; => T
(and 0 t)              ; => T
(or 0 nil)             ; => 0

;;; Character

#\A                    ; => #\A
#\λ                    ; => #\GREEK_SMALL_LETTER_LAMDA
#\u03BB                ; => #\GREEK_SMALL_LETTER_LAMDA

;;; String ialah array character yang tidak berubah panjang

"Hello, world!"
"Benjamin \"Bugsy\" Siegel"   ; backslash ialah escape character

;;; String boleh digabungkan

(concatenate 'string "Hello, " "world!") ; => "Hello, world!"

;;; String boleh diperlakukan seperti urutan character

(elt "Apple" 0) ; => #\A

;;; FORMAT digunakan untuk output mengikut format, daripada penggubahan string
;;; yang simple sehinggalah loop dan conditional. Argument pertama untuk FORMAT
;;; menentukan ke mana string akan pergi. Jika NIL, FORMAT
;;; akan pulangkan string sebagai data string; jika T, FORMAT akan output
;;; ke standard output, biasanya di screen, kemudian pulangkan NIL.

(format nil "~A, ~A!" "Hello" "world")   ; => "Hello, world!"
(format t "~A, ~A!" "Hello" "world")     ; => NIL


;;;-----------------------------------------------------------------------------
;;; 2. Variable
;;;-----------------------------------------------------------------------------

;;; Anda boleh membuat variable global (dynamically scoped) menggunakan DEFVAR dan
;;; DEFPARAMETER. Nama variable boleh guna mana-mana character kecuali: ()",'`;#|\

;;; Beza antara DEFVAR dengan DEFPARAMETER ialah DEFVAR tidak akan ubah nilai
;;; variable jika dijalankan semula. Manakala DEFPARAMETER, akan mengubah nilai
;;; jika dijalankan semula.

;;; Kebiasaannya, variable global diletakkan earmuff (asterisk) pada nama.

(defparameter *some-var* 5)
*some-var* ; => 5

;;; Anda juga boleh menggunakan character unicode.
(defparameter *AΛB* nil)

;;; Variable yang tidak wujud boleh diakses tetapi akan menyebabkan undefined
;;; behavior. Jangan buat.

;;; Anda boleh membuat local binding menggunakan LET. Dalam snippet berikut, `me`
;;; terikat dengan "dance with you" hanya dalam (let ...). LET mesti akan pulangkan
;;; nilai `form` yang paling terakhir.

(let ((me "dance with you")) me) ; => "dance with you"


;;;-----------------------------------------------------------------------------;
;;; 3. Struct dan collection
;;;-----------------------------------------------------------------------------;


;;; Struct

(defstruct dog name breed age)
(defparameter *rover*
    (make-dog :name "rover"
              :breed "collie"
              :age 5))
*rover*            ; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5)
(dog-p *rover*)    ; => T
(dog-name *rover*) ; => "rover"

;;; DOG-P, MAKE-DOG, dan DOG-NAME semuanya dibuat oleh DEFSTRUCT secara automatik


;;; Pair

;;; CONS membuat pair. CAR dan CDR pulangkan head (kepala) dan tail (ekor) CONS-pair.

(cons 'SUBJECT 'VERB)         ; => '(SUBJECT . VERB)
(car (cons 'SUBJECT 'VERB))   ; => SUBJECT
(cdr (cons 'SUBJECT 'VERB))   ; => VERB


;;; List

;;; List ialah data structure linked-list, dihasilkan daripada pair CONS dan
;;; berakhir dengan NIL (atau '()) menandakan akhirnya list tersebut

(cons 1 (cons 2 (cons 3 nil)))     ; => '(1 2 3)

;;; LIST ialah constructor untuk memudahkan penghasilan list

(list 1 2 3)                       ; => '(1 2 3)

;;; Apabila argument pertama untuk CONS ialah atom dan argument kedua ialah
;;; list, CONS akan pulangkan CONS-pair baru dengan argument pertama sebagai
;;; item pertama dan argument kedua sebagai CONS-pair yang lain

(cons 4 '(1 2 3))                  ; => '(4 1 2 3)

;;; Gunakan APPEND untuk menggabungkan list

(append '(1 2) '(3 4))             ; => '(1 2 3 4)

;;; Atau CONCATENATE

(concatenate 'list '(1 2) '(3 4))  ; => '(1 2 3 4)

;;; List ialah type utama, jadi ada pelbagai function untuk mengendalikan
;;; list, contohnya:

(mapcar #'1+ '(1 2 3))             ; => '(2 3 4)
(mapcar #'+ '(1 2 3) '(10 20 30))  ; => '(11 22 33)
(remove-if-not #'evenp '(1 2 3 4)) ; => '(2 4)
(every #'evenp '(1 2 3 4))         ; => NIL
(some #'oddp '(1 2 3 4))           ; => T
(butlast '(subject verb object))   ; => (SUBJECT VERB)


;;; Vector

;;; Vector ialah array yang tidak berubah panjang

#(1 2 3) ; => #(1 2 3)

;;; Gunakan CONCATENATE untuk menggabungkan vector

(concatenate 'vector #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6)


;;; Array

;;; Vector dan string adalah sejenis array.

;;; 2D array

(make-array (list 2 2))         ; => #2A((0 0) (0 0))
(make-array '(2 2))             ; => #2A((0 0) (0 0))
(make-array (list 2 2 2))       ; => #3A(((0 0) (0 0)) ((0 0) (0 0)))

;;; Perhatian: nilai awal MAKE-ARRAY adalah bergantung kepada jenis Common Lisp.
;;; Untuk meletakkan nilai awal secara manual:

(make-array '(2) :initial-element 'unset)  ; => #(UNSET UNSET)

;;; Untuk mengakses element di kedudukan 1, 1, 1:

(aref (make-array (list 2 2 2)) 1 1 1)     ;  => 0


;;; Adjustable vector (vector yang boleh berubah)

;;; Adjustable vector mempunyai rupa yang sama dengan
;;; vector yang tidak berubah panjang.

(defparameter *adjvec* (make-array '(3) :initial-contents '(1 2 3)
                                   :adjustable t :fill-pointer t))
*adjvec* ; => #(1 2 3)

;;; Tambah element baru

(vector-push-extend 4 *adjvec*)   ; => 3
*adjvec*                          ; => #(1 2 3 4)


;;; Set hanyalah list:

(set-difference '(1 2 3 4) '(4 5 6 7))   ; => (3 2 1)
(intersection '(1 2 3 4) '(4 5 6 7))     ; => 4
(union '(1 2 3 4) '(4 5 6 7))            ; => (3 2 1 4 5 6 7)
(adjoin 4 '(1 2 3 4))                    ; => (1 2 3 4)

;;; Tetapi, anda perlukan data structure yang lebih baik untuk digunakan dengan
;;; data set yang sangat banyak

;;; Kamus dibuat menggunakan hash table.

;;; Bina hash table

(defparameter *m* (make-hash-table))

;;; Tetapkan nilai

(setf (gethash 'a *m*) 1)

;;; Baca nilai

(gethash 'a *m*) ; => 1, T

;;; CL boleh memulangkan beberapa nilai (multiple value).

(values 1 2) ; => 1, 2

;;; dan boleh digunakan dengan MULTIPLE-VALUE-BIND untuk bind setiap nilai

(multiple-value-bind (x y)
    (values 1 2)
  (list y x))

; => '(2 1)

;;; GETHASH antara contoh function yang memulangkan multiple value. Value
;;; pertama ialah nilai untuk key dalam hash table; jika key tidak
;;; jumpa GETHASH akan pulangkan NIL.

;;; Value kedua menentukan sama ada key tersebut betul-betul wujud dalam hash
;;; table. Jika key tidak jumpa dalam table value tersebut ialah NIL. Cara ini
;;; membolehkan kita untuk periksa sama ada value untuk key ialah NIL.

;;; Dapatkan value yang tidak wujud akan pulangkan nil

(gethash 'd *m*) ;=> NIL, NIL

;;; Anda boleh menentukan value default untuk key yang tidak wujud

(gethash 'd *m* :not-found) ; => :NOT-FOUND

;;; Jom lihat penggunaan multiple return value di dalam code.

(multiple-value-bind (a b)
    (gethash 'd *m*)
  (list a b))
; => (NIL NIL)

(multiple-value-bind (a b)
    (gethash 'a *m*)
  (list a b))
; => (1 T)


;;;-----------------------------------------------------------------------------
;;; 3. Function
;;;-----------------------------------------------------------------------------

;;; Gunakan LAMBDA untuk membuat anonymous function. Function sentiasa memulangkan
;;; value untuk expression terakhir.

(lambda () "Hello World") ; => #<FUNCTION (LAMBDA ()) {1004E7818B}>

;;; Gunakan FUNCALL untuk memanggil anonymous function

(funcall (lambda () "Hello World"))   ; => "Hello World"
(funcall #'+ 1 2 3)                   ; => 6

;;; Panggilan kepada FUNCALL juga boleh terjadi apabila lambda tersebut ialah CAR
;;; (yang pertama) untuk list (yang tidak mempunyai tanda petikan)

((lambda () "Hello World"))           ; => "Hello World"
((lambda (val) val) "Hello World")    ; => "Hello World"

;;; FUNCALL digunakan apabila argument sudah diketahui. Jika tidak, gunakan APPLY

(apply #'+ '(1 2 3))   ; => 6
(apply (lambda () "Hello World") nil) ; => "Hello World"

;;; Untuk menamakan sebuah function, guna DEFUN

(defun hello-world () "Hello World")
(hello-world) ; => "Hello World"

;;; Simbol () di atas bermaksud list kepada argument

(defun hello (name) (format nil "Hello, ~A" name))
(hello "Steve") ; => "Hello, Steve"

;;; Function boleh ada argument optional (tidak wajib); argument tersebut bernilai
;;; NIL secara default

(defun hello (name &optional from)
  (if from
      (format t "Hello, ~A, from ~A" name from)
      (format t "Hello, ~A" name)))

(hello "Jim" "Alpacas")       ; => Hello, Jim, from Alpacas

;;; Nilai default boleh ditetapkan untuk argument tersebut

(defun hello (name &optional (from "The world"))
   (format nil "Hello, ~A, from ~A" name from))

(hello "Steve")               ; => Hello, Steve, from The world
(hello "Steve" "the alpacas") ; => Hello, Steve, from the alpacas

;;; Function juga mempunyai keyword argument untuk membolehkan argument diletakkan
;;; tidak mengikut kedudukan

(defun generalized-greeter (name &key (from "the world") (honorific "Mx"))
  (format t "Hello, ~A ~A, from ~A" honorific name from))

(generalized-greeter "Jim")
; => Hello, Mx Jim, from the world

(generalized-greeter "Jim" :from "the alpacas you met last summer" :honorific "Mr")
; => Hello, Mr Jim, from the alpacas you met last summer


;;;-----------------------------------------------------------------------------
;;; 4. Kesamaan
;;;-----------------------------------------------------------------------------

;;; CL mempunyai sistem kesaksamaan yang canggih. Antaranya adalah seperti berikut.

;;; Untuk nombor, guna `='
(= 3 3.0)               ; => T
(= 2 1)                 ; => NIL

;;; Untuk identiti object (lebih kurang) guna EQL
(eql 3 3)               ; => T
(eql 3 3.0)             ; => NIL
(eql (list 3) (list 3)) ; => NIL

;;; untuk list, string, dan bit-vector, guna EQUAL
(equal (list 'a 'b) (list 'a 'b)) ; => T
(equal (list 'a 'b) (list 'b 'a)) ; => NIL


;;;-----------------------------------------------------------------------------
;;; 5. Control Flow
;;;-----------------------------------------------------------------------------

;;; Conditional (syarat)

(if t                ; test expression
    "this is true"   ; then expression
    "this is false") ; else expression
; => "this is true"

;;; Dalam conditional, semua value yang bukan NIL ialah true

(member 'Groucho '(Harpo Groucho Zeppo)) ; => '(GROUCHO ZEPPO)
(if (member 'Groucho '(Harpo Groucho Zeppo))
    'yep
    'nope)
; => 'YEP

;;; Guna COND untuk meletakkan beberapa test
(cond ((> 2 2) (error "wrong!"))
      ((< 2 2) (error "wrong again!"))
      (t 'ok)) ; => 'OK

;;; TYPECASE adalah seperti switch tetapi untuk data type value tersebut
(typecase 1
  (string :string)
  (integer :int))
; => :int


;;; Loop

;;; Recursion

(defun fact (n)
  (if (< n 2)
      1
    (* n (fact(- n 1)))))

(fact 5) ; => 120

;;; Iteration

(defun fact (n)
  (loop :for result = 1 :then (* result i)
     :for i :from 2 :to n
     :finally (return result)))

(fact 5) ; => 120

(loop :for x :across "abc" :collect x)
; => (#\a #\b #\c #\d)

(dolist (i '(1 2 3 4))
  (format t "~A" i))
; => 1234


;;;-----------------------------------------------------------------------------
;;; 6. Mutation
;;;-----------------------------------------------------------------------------

;;; Guna SETF untuk meletakkan nilai baru untuk variable yang sedia ada. Ini sama
;;; seperti contoh hash table di atas.

(let ((variable 10))
    (setf variable 2))
; => 2

;;; Sebaik-baiknya kurangkan penggunaan destructive function dan elakkan
;;; mutation jika boleh.


;;;-----------------------------------------------------------------------------
;;; 7. Class dan object
;;;-----------------------------------------------------------------------------

;;; Takde dah class untuk haiwan. Jom buat Human-Powered Mechanical
;;; Conveyances (Kenderaan Mekanikal Berkuasa Manusia).

(defclass human-powered-conveyance ()
  ((velocity
    :accessor velocity
    :initarg :velocity)
   (average-efficiency
    :accessor average-efficiency
   :initarg :average-efficiency))
  (:documentation "A human powered conveyance"))

;;; Argument untuk DEFCLASS, mengikut susunan ialah:
;;; 1. nama class
;;; 2. list untuk superclass
;;; 3. list untuk slot
;;; 4. specifier optional (tidak wajib)

;;; Apabile list untuk superclass tidak ditetapkan, list yang kosong bermaksud
;;; class standard-object. Ini *boleh* ditukar, kalau anda tahu apa yang anda buat.
;;; Baca Art of the Metaobject Protocol untuk maklumat lebih lanjut.

(defclass bicycle (human-powered-conveyance)
  ((wheel-size
    :accessor wheel-size
    :initarg :wheel-size
    :documentation "Diameter of the wheel.")
   (height
    :accessor height
    :initarg :height)))

(defclass recumbent (bicycle)
  ((chain-type
    :accessor chain-type
    :initarg :chain-type)))

(defclass unicycle (human-powered-conveyance) nil)

(defclass canoe (human-powered-conveyance)
  ((number-of-rowers
    :accessor number-of-rowers
    :initarg :number-of-rowers)))

;;; Panggilan DESCRIBE kepada class HUMAN-POWERED-CONVEYANCE di REPL akan memberi:

(describe 'human-powered-conveyance)

; COMMON-LISP-USER::HUMAN-POWERED-CONVEYANCE
;  [symbol]
;
; HUMAN-POWERED-CONVEYANCE names the standard-class #<STANDARD-CLASS
;                                                    HUMAN-POWERED-CONVEYANCE>:
;  Documentation:
;    A human powered conveyance
;  Direct superclasses: STANDARD-OBJECT
;  Direct subclasses: UNICYCLE, BICYCLE, CANOE
;  Not yet finalized.
;  Direct slots:
;    VELOCITY
;      Readers: VELOCITY
;      Writers: (SETF VELOCITY)
;    AVERAGE-EFFICIENCY
;      Readers: AVERAGE-EFFICIENCY
;      Writers: (SETF AVERAGE-EFFICIENCY)

;;; Perhatikan apa yang berlaku. CL memang direka sebagai sistem interaktif.

;;; Untuk membuat method, jom kira berapa panjang lilitan untuk
;;; roda basikal menggunakan formula: C = d * pi

(defmethod circumference ((object bicycle))
  (* pi (wheel-size object)))

;;; Nilai PI memang sudah ada dalam CL

;;; Katakanlah kita ingin ambil tahu efficiency value (nilai keberkesanan)
;;; rower (pendayung) di dalam canoe (perahu) adalah berbentuk logarithmic. Ini
;;; boleh ditetapkan di dalam constructor/initializer.

;;; Untuk initialize instance selepas CL sudah siap construct:

(defmethod initialize-instance :after ((object canoe) &rest args)
  (setf (average-efficiency object)  (log (1+ (number-of-rowers object)))))

;;; Kemudian untuk construct sesebuah instance dan periksa purata efficiency...

(average-efficiency (make-instance 'canoe :number-of-rowers 15))
; => 2.7725887


;;;-----------------------------------------------------------------------------
;;; 8. Macro
;;;-----------------------------------------------------------------------------

;;; Macro membolehkan anda untuk menambah syntax language. CL tidak ada
;;; WHILE loop, tetapi, kita boleh mencipta syntax ter. Jika kita buat menggunakan
;;; naluri, kita akan dapat:

(defmacro while (condition &body body)
    "While `condition` is true, `body` is executed.
`condition` is tested prior to each execution of `body`"
    (let ((block-name (gensym)) (done (gensym)))
        `(tagbody
           ,block-name
           (unless ,condition
               (go ,done))
           (progn
           ,@body)
           (go ,block-name)
           ,done)))

;;; Jom lihat versi yang lebih high-level:

(defmacro while (condition &body body)
    "While `condition` is true, `body` is executed.
`condition` is tested prior to each execution of `body`"
  `(loop while ,condition
         do
         (progn
            ,@body)))

;;; Namun, dengan compiler yang modern, cara ini tidak diperlukan; form LOOP
;;; compile sama sahaja dan juga mudah dibaca.

;;; Perhatikan ``` digunakan, sama juga `,` dan `@`. ``` ialah operator jenis quote
;;; yang dipanggil quasiquote; operator tersebut membolehkan penggunaan `,` .
;;; `,` membolehkan variable "di-unquote-kan". @ mengembangkan list.

;;; GENSYM membuat simbol unik yang pasti tidak wujud di tempat-tempat yang
;;; lain. Ini kerana macro dikembangkan semasa compile dan
;;; nama variable di dalam macro boleh bertembung dengan nama variable yang
;;; digunakan dalam code yang biasa.

;;; Baca Practical Common Lisp dan On Lisp untuk maklumat lebih lanjut mengenai macro.
```


## Bacaan lanjut

- [Practical Common Lisp](http://www.gigamonkeys.com/book/)
- [Common Lisp: A Gentle Introduction to Symbolic Computation](https://www.cs.cmu.edu/~dst/LispBook/book.pdf)


## Maklumat tambahan

- [CLiki](http://www.cliki.net/)
- [common-lisp.net](https://common-lisp.net/)
- [Awesome Common Lisp](https://github.com/CodyReichert/awesome-cl)
- [Lisp Lang](http://lisp-lang.org/)


## Kredit

Terima kasih banyak diucapkan kepada ahli Scheme yang membuat permulaan yang sangat
bagus dan mudah untuk diguna pakai untuk Common Lisp.

- [Paul Khuong](https://github.com/pkhuong) untuk review yang bagus.