Commonlisp小ネタ集

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


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

```common-lisp: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関数は型を混在できます。

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

## array

### eltは汎用的に使える
arrayのアクセスはarefやsvrefで行うと思いますがeltでもアクセスできます。

## 数学処理
### 最大公倍数、最大公約数
lcm
最小公倍数 
gcd
最大公約数
引数は任意の個数です。

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

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

```common-lisp:minus.lisp
* (- 10)
;-10
* (- 10 0)
;10
```

### 少数を分数にする
rationalize

```common-lisp:rationalize.lisp
* (rationalize 1.1)
;11/10
```

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

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


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

## 破壊的代入
### shiftfマクロ
右側に詰めるように値を入れます。
### rotatefマクロ
値を回転させるように入れ替えます。シンボル同士で値を入れ替えたりする場面で使います。

```common-lisp: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をとります。

```common-lisp: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か)を判定します。

```common-lisp: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

```common-lisp: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

```common-lisp: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マクロ

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

```common-lisp
(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で探しましょう。