4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Commonlisp小ネタ集

Last updated at Posted at 2020-03-13

はじめに

Commonlispの小ネタ集です。
マイナー関数や小技、ハマりポイント等を紹介します。適時書き足します。

list

値を書き換え

sublis関数はlistの値を書き換えます。listの内部にあっても書き換えられます。

sublis.lisp
*(sublis '((1 . 100)) '(100 (1) 1))
;(100 (100) 100)

cdrはcdddrまで、firstはtenthまで

文字通りです。(個人的には3要素超えたらnthやeltなどでアクセスすべきだと思います)

popはnilでもできる

nilをpopするとnilが返ります。

string

連結

concatenate関数
concatenate関数は型を混在できます。

truncate.lisp
* (concatenate 'string "abc" "def")
;"abcdef"
;concatenateはsequenceを混在できます。
* (concatenate 'string '(#\a #\b #\c) "def")
;"abcdef"

array

eltは汎用的に使える

arrayのアクセスはarefやsvrefで行うと思いますがeltでもアクセスできます。

数学処理

最大公倍数、最大公約数

lcm
最小公倍数
gcd
最大公約数
引数は任意の個数です。

lcm-gcd.lisp
* (lcm 2 5)
;10
* (gcd 20 30)
;10

-関数の特性

-関数は1引数の場合1引数の負を返します。

minus.lisp
* (- 10)
;-10
* (- 10 0)
;10

少数を分数にする

rationalize

rationalize.lisp
* (rationalize 1.1)
;11/10

分数から少数に変換した時の桁を増やす

floatは10^-8までしか表現できないため桁数が不足する場合があります。coerseでdouble-floatやlong-floatに変換しましょう。

float.lisp
* (coerce 1/3 'double-float)
;0.3333333333333333d0

素数判定

(sbclのみ)
sbclの組み込み関数でsb-int:positive-primepは自然数が素数であるかを判定します。引数以下の数字で割れるかを確かめているため計算効率は悪いです。

破壊的代入

shiftfマクロ

右側に詰めるように値を入れます。

rotatefマクロ

値を回転させるように入れ替えます。シンボル同士で値を入れ替えたりする場面で使います。

shiftf-rotatef.lisp
(let* ((a 1)
       (b 2)
       (c 3))
  (shiftf a b c)
  (format t "a:~A b:~A c:~A~%" a b c) ;a:2 b:3 c:3
  (shiftf a b c)
  (format t "a:~A b:~A c:~A~%" a b c)) ;a:3 b:3 c:3
(let* ((a 1)
       (b 2)
       (c 3))
  (rotatef a b c)
  (format t "a:~A b:~A c:~A~%" a b c) ;a:2 b:3 c:1 
  (rotatef a b c)
  (format t "a:~A b:~A c:~A~%" a b c)) ;a:3 b:1 c:2

map

map関数のand/orを取る

every
some
everyはand、someはorをとります。

some-every.lisp
(every #'evenp '(2 4 6));T
(some #'evenp '(1 2 3));T

入出力

###yesかnoの入力を待ちたい
yes-or-no-p y-or-n-p
入力がyesかnoか(yかnか)を判定します。

yes-or-no-p.lisp
(yes-or-no-p "yes?no?")
;yes?no? (yes or no) 
;a
;Please type "yes" for yes or "no" for no.
;yes?no? (yes or no)
;n
;Please type "yes" for yes or "no" for no.
;yes?no? (yes or no)
;no
;nil

その他

型を調べる

type-of
詳細に調べたいときはdescribe

describe.lisp
(type-of t)
;BOOLEAN
*(describe t)
;COMMON-LISP:T
;  [symbol]
;
;T names a constant variable:
;  Value: T
;
;T names the system-class #<SB-PCL:SYSTEM-CLASS COMMON-LISP:T>:
;  Class precedence-list: T
;  Direct subclasses: ARRAY, SIMD-PACK, NUMBER, SB-KERNEL::RANDOM-CLASS,
;                     SB-KERNEL:FDEFN, SB-KERNEL:CODE-COMPONENT,
;                     WEAK-POINTER, SYSTEM-AREA-POINTER, SYMBOL,
;                     CHARACTER, SB-PCL::SLOT-OBJECT, SEQUENCE, STREAM,
;                     FUNCTION
;  No direct slots.


再帰関数の展開を見たい

trace

trace.lisp
*(defun f (x)
   (if (= x 1) 1 (* x (f (1- x)))))
*(trace f)
*(f 5)
;
;  0: (F 5)
;    1: (F 4)
;      2: (F 3)
;        3: (F 2)
;          4: (F 1)
;          4: F returned 1
;        3: F returned 2
;      2: F returned 6
;    1: F returned 24
;  0: F returned 120

*(untrace f)
*(f 5)
;120

常に何かを返す関数が欲しい

constantly関数で作成します。

マクロを関数化したい

macro-functionマクロ

任意の添字付きでループを回したい

(loop :for j :from 1
      :for k :in (concatenate 'list "test")
      :do(print (cons j k)))
;(1 . #\t) 
;(2 . #\e) 
;(3 . #\s) 
;(4 . #\t)

loopマクロでforが複数ある場合は最短のforが優先されるのでkが終了したら止まります

ハマりポイント

listは要素のアクセスにO(n)かかる

listはconsセルをたどる実装なのでO(n)かかります。後ろからアクセスしたい場合はreverseしたものを置いておくかarrayを使いましょう。またmapcarやreduce関数はcdrで遷移するためO(n^2)ではなくO(n)で済みます。

tに値は束縛できない

tはcommonlispではtrueを示すためシンボルとして用いることはできません。
他の言語では一時変数として使われることも多いためそのまま書くとたまにハマります。

loopマクロのacross節、map関数はvectorをとる

vectorは1次元のarrayです。つまり2次元以上のarrayをそのまま処理することはできません。

findは探査する要素を返す

find関数は探査する要素を返すのでnilを探査するとnilを返します。このためcount=0かpositionで探しましょう。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?