高階関数クイズをやった

これ。

unlambdaとかlazy k(というかコンビネータ論理)を思い出した。
以下は答えそのものじゃないけど、思考手順が書いてあるので見たくない人はみない事。




とりあえず「twice twice twice add1 0 => 16」までは手で展開してみたものの、次のでどうも手ではやってられなさそうな気配になったので、ちゃんと変換ルールを考える事に。

自分はLisperなので、まずひたすら括弧をつけた。

(f x)                                 ; twice0
((twice f) x)                         ; twice1
(((twice twice) f) x)                 ; twice2
((((twice twice) twice) f) x)         ; twice3
(((((twice twice) twice) twice) f) x) ; twice4

それから、手でtwice3まで展開してみて、その結果を眺めた。
展開

(f x)                                 ; twice0
(f (f x))                             ; twice1
(f (f (f (f x))))                     ; twice2
(f (f ... (f (f x))))...))            ; twice3(fは16個)

「twiceが一個増える毎に、展開結果のfがたくさん増える」というルールのようだ。
ここでtwiceというコンビネータは実際にはどういう意味なのかを類推した結果、答えに辿りついた。


答えがあっているか、Gaucheで検算した。

(define ((twice f) x)
  (f (f x)))
(define (add1 x)
  (+ 1 x))

;; 上の式を流用できるように定義する
(define f add1)
(define x 0)

;; 上の式をコピペした
(f x)                                 ; twice0
((twice f) x)                         ; twice1
(((twice twice) f) x)                 ; twice2
((((twice twice) twice) f) x)         ; twice3
(((((twice twice) twice) twice) f) x) ; twice4

あってた。