Yet Another Common Lisp Problems #4 my-last, my-butlast

●問題4

リスト xs の最後尾を求める関数 last と、最後尾の要素を取り除く関数 butlast を定義してください。Common Lisp には同等の機能を持つ関数 last と butlast がありますので、ここでは関数名を my-last と my-butlast としました。

> (my-last '(a b c))
(c)
> (my-last '(a))
(a)
> (my-butlast '(a b c))
(a b)
> (my-butlast '(a))
()

解答

ホームページ移転のお知らせ - Yahoo!ジオシティーズ
(defun my-last (list)
  (if (null (cdr list))
    list
    (my-last (cdr list))))
=> my-last

(defun my-butlast (list)
  (if (null (cdr list))
    nil
    (cons (car list) (my-butlast (cdr list)))))
=> my-butlast

ネタを思いつかないので extended loop で書いてみようと思ったが (loop for x in list collect ...) くらいしか使い方を知らないのでググったらわかりやすいページを発見。

(loop for VAR on LIST ..) で cdr を歩けるらしい。

(require "cmu_loop")

(defun my-last/loop (list)
  (loop for x on list
    when (null (cdr x))
    return x))

でいいような気がするんだけど "Invalid clause for inside a conditional: return" と怒られる。で結局こうした。

(defun my-last/loop (list)
  (loop for x on list
    when (null (cdr x))
    do (return x)))

cmu_loop が完全に Common Lisp 準拠ではないのは知ってたけど、実際躓くとどう書けるのか調べる方法が書いて動かしてみるしかないってのはしんどかった。疲れたので my-butlast/loop はキャンセル。