Common Lisp

do, dolist, dotimes

do

(do (variable-definition*)
    (end-test-form result-form*)
  statement*)

dolist

;;; (dotimes (var limit result) S式)
(dolist (x '(0 1 2 3 4)) (print x))

dotimes

;;; (dolist (var init-form result) S式)
(dotimes (x 5) (print x))

例: フィボナッチ

(do ((n 0 (1+ n))
     (cur 0 next)
     (next 1 (+ cur next)))
    ((= 10 n) cur))

次の二つは同じ.

(dotimes (i 4) (print i))
(do ((i 0 (1+ i)))
    ((>= i 4))
  (print i))

fold

Common Lisp では reduce.

(reduce #'max '(1 2 3 4))

format

基本

(format t "hello, world")
(format t "hello, ~a" '(1 2 3))
(format t "x: ~d y: ~d" 20.1 3)

注意

直接数は渡せないので "~a" の仲介が必要.

(format t "~a" 3)

値の文字列化

(format t "hello, world")tnil にすると数値を文字列化できる.

loop

いろいろな使い方ができる化け物マクロなので, 少しずつためていく.

整数からなるリストを作る

(loop :for i :below 5 :collect i)
(loop for i from 1 to 10 collecting i)

二重ループ

(loop for x downfrom 999 to 900
      append (loop for y downfrom 999 to 900
                   collect (format nil "~a" (* x y))))

while

(let ((i 0) (fibval 0) (fibs ())
      (xs ())
      (lastval 4000000))
  (loop while (< fibval lastval)
        do (progn
             (setq fibval (fib-memo i)
                        i (incf i))
             (when (< fibval lastval)
               (setq fibs (cons fibval fibs))))))))

MISC

(loop for x from 1 to 10 summing (expt x 2)) ;==> 385
(loop :for i :from 3 :upto 5 :do (print i))
(loop :repeat 5 :do (format t "~&five"))
(loop :for i :upto 5 :do (format t "~&~A" i))

;;; This counts the number of vowels in a string:
(loop for x across "the quick brown fox jumps over the lazy dog"
      counting (find x "aeiou"))

mapcar

詳しくは hyperspec 参照. map だと書式が違う.

(print (mapcar #'1+ '(1 2 3)))

remove-if-not: いわゆる filter

(remove-if-not #'(lambda (x) (if (oddp x) (1+ x)))
               '(1 2 3 4))

paredit

progn: 一箇所に処理をたくさん書きたいとき

loop while dodo のように, 1 つのフォームしか書けないところでたくさん処理を書きたいときは, progn でくくった中に書けばいい.

SLIME

有用コマンド

コマンド 意味
C-c RET マクロ展開

関数のクォート

(defun sq (x) (* x x))
(mapcar #'sq '(1 2 3 4))

述語式

=, eq, equal, equalp

条件文

cond

(cond
    ((equal (mod x 3) 0) x)
    ((equal (mod x 5) 0) x))
    (t x))

if

(if (3or5p 4)
    1
    2)

when

(when (3or5p 4)
  1)

数学関係

累乗

(expt 2 3) ; 2^3

ハッシュテーブル・連想リスト

Python でいう dictionary のこと.

;;; ハッシュテーブル
(let ((hash (make-hash-table)))
  (setf (gethash 'color hash) 'red)
  (setf (gethash 'height hash) 185)
  (setf (gethash 'weight hash) 110)
  (setf (gethash 'name hash) "Mukku")
  (maphash #'(lambda (k v) (format t "~a => ~a~%" k v)) hash)
  (loop for key being each hash-key of hash
      using (hash-value value)
      do (format t "~A => ~A~%" key value))
  )
;;; 連想リスト
(let ((alst '()))
  (push '(:color :red) alst)
  (push '(height 185) alst)
  (push '(weight 110) alst)
  (format t "~&~a" (assoc :color alst))
  (format t "~&~a" (assoc 'height alst))
  (format t "~&~a" (assoc 'weight alst))
  (format t "~&~a" alst))

マクロ展開

Backquote Syntax Equivalent List-Building Code Result
`(a (+ 1 2) c) (list 'a '(+ 1 2) 'c) (a (+ 1 2) c)
`(a ,(+ 1 2) c) (list 'a (+ 1 2) 'c) (a 3 c)
`(a (list 1 2) c) (list 'a '(list 1 2) 'c) (a (list 1 2) c)
`(a ,(list 1 2) c) (list 'a (list 1 2) 'c) (a (1 2) c)
`(a ,@(list 1 2) c) (append (list 'a) (list 1 2) (list 'c)) (a 1 2 c)

メモ化

;;; https://takeokunn.xyz/blog/post/common-lisp-fibonacci
;;; フィボナッチ数列
(defun memo (fn)
  (let ((table (make-hash-table :test 'equal)))
    #'(lambda (&rest rest)
        (multiple-value-bind (val found-p) (gethash rest table)
          (if found-p
              val
              (setf (gethash rest table) (apply fn rest)))))))
(defun memoize (fn-name)
  (setf (symbol-function fn-name)
        (memo (symbol-function fn-name))))
(defmacro defun-memo (fn args &body body)
  `(memoize (defun ,fn ,args . ,body)))
(defun fib (n)
  (if (<= n 1) 1
      (+ (fib (- n 1)) (fib (- n 2)))))
(defun-memo fib-memo (n)
  (if (<= n 1) 1
      (+ (fib-memo (- n 1)) (fib-memo (- n 2)))))

文字列

文字を数値化

(digit-char-p "test")

文字列を数値化

(parse-integer "1")
(parse-integer "11" :radix 2)
(parse-integer "11" :radix 8)
(parse-integer "11" :radix 10)
(parse-integer "11" :radix 16)
(read-from-string "1/10")
(read-from-string "1.2")
(read-from-string "#c(1 1)")

反転

(reverse "1234")

リストとその処理

最大値を取る

(reduce #'max '(1 2 3 4))