2018年1月24日水曜日

fletとletf

 「Land of Lisp」ではじめてfletというものを知った。
 letの関数版。関数内にローカルの関数をつくれるものらしい。elispにもcl.elにあった。同じようなことはletの変数にlambdaをセットしてfuncallしてやってみたことはあるけれど。
 便利そうだけど、あんまり使わないかも、とか、思っていたら。
 そういやつくった関数に何か皮をかぶせた処理をいれたい、とか、よくあることだった。そういうときは別の関数をつくって皮をかぶせていたけれど、fletに押し込んでやれば、いいのか……。
 なるほど。

 で、fletの*HELP*を読んでいたらletfというものがあることを知る。

(setq wrk '(1 2 3))
(1 2 3)

(cl-letf (((nth 1 wrk) 44))
  (nth 1 wrk))
44

wrk
(1 2 3)

 おっ、すげえ、と思ったけれど。

(cl-letf (((nth 1 wrk) 44))
  wrk)
(1 2 3)

 となってしまった。
 なんとなく、(1 44 3)が返ってくるような気がしていたのだけど。
 もしかしたら(nth 1 wrk)の部分を44に差し替えているだけなのかな? と思ってmacroexpandしてみたら。

(macroexpand '(cl-letf (((nth 1 wrk) 44))
        (nth 1 wrk)))

(let* ((c (nthcdr 1 wrk)) 
       (old (car c)))
  (unwind-protect 
      (progn (setcar c 44)
      (nth 1 wrk))
    (setcar c old)))

(macroexpand '(cl-letf (((nth 1 wrk) 44))
  wrk))
(let* ((c (nthcdr 1 wrk)) (old (car c)))
  (unwind-protect (progn (setcar c 44) 
    wrk) 
    (setcar c old)))

 あれ?
 最初のやつは44が返ってくるのに、なんで二番目のやつは(1 44 3)が返ってこないんだろう……? というか、CommonLispにはデフォルトでletfってないのかな。「undefined function: LETF」になってしまったけど。

メモ:
#:g1: Emacs Lispのcl-fletは使いものにならないなんてことはない