[haskell] twice twice twice

 > twice twice succ 0
 4
 > twice twice twice succ 0
 16

でビビったり。とかなさけない。

しばらくいじってなかったらだいぶ感覚鈍っていて、というか以前やった時もあんまり理解できていなかったんだなと少し反省を重ねつつも、全く成長しない自分に相変わらずの嫌悪感を持つふりをしながらも、結局は自分に甘いじじい青二才。
だなーと思いながら、 twice を重ねた時の挙動をやっとこさ理解できたのでメモ。

定義から

 twice f x = f (f x)

ということはカリーな感じで

 twice  f = \x -> f (f x)

2つならどーだ

        twice twice
        ==> \f -> twice (twice f) 
        ==> \f -> (\x -> (twice f) ((twice f) x))
        ==> \f -> (\x -> (\y -> (f (f y)) ((\y -> (f (f y))) x) ))
        ==> \f -> (\x -> (\y -> (f (f y)) (f (f x))))
        ==> \f -> (\x -> (f (f (f (f x)))) )

あーなるほど。

本番

        twice twice twice
        ==> \f -> (\x -> (f (f (f (f x)))) ) twice 
        ==> \x -> (twice (twice (twice (twice x))))

ぎゃー。しかし twice ( twice x ) が上の通りであることを考えれば

        ==> \x -> \f -> { (f (f (f (f x))))) } が4段分

で結局 16となるわけか。

概念としては

((twice twice) twice) succ)

とゆーのは素直に 「二回(二回を(二回分 ( succ))) する」でよいわけか。
んでとどのつまり 2^2^2と考えればよいわけですね。

じゃあtripleなら

3^3^3になるのかな、と思ったけど7,625,597,484,987だからだめだーと

> triple f x = f ( f( f x))
> triple succ 0
3
> triple triple succ 0
27

3^3で日和ってみた。あと (3^3)^3とか

> triple (triple triple) succ 0
19683

ちょうどひっくり返るのかひっくり返らない。そのまま!いややっぱりひっくり返る!ww(アホか僕) おもしろい。

他人のワーク

先に文献レビューをするのがアカデミックなのでしょうが、ダメ人間なので後から探したりなど。
http://spivey.oriel.ox.ac.uk/corner/Twice_twice_twice
まんまのがあった。しかも処理系にpretty printさせてるのでカッケー

駄菓子菓子、Haskellの関数適用は左結合だから

reduce (Ap (Ap Twice f) x) = return (Ap f (Ap f x))

これはおかしいんじゃないだろうか?これだと 後ろのTwiceが先に評価されない?

余談ですが

Tonight, Tonight, Tonight はけっこー好きです。

追記:
ややこしいことしてたけど、

 twice f = f.f

とすれば思っきし自明。悩む価値もなかったりなんぞした。

 twice twice f ==> (twice . twice) f ==> twice ( f.f ) = (f.f).(f.f)
 twice twice twice f ==> (twice twice twice) f 
              { ( twice twice f ) = f.f.f.fより }
                                  ==> (twice.twice.twice.twice) f
                                  ==> (twice.twice.twice (f . f))
                                  ==> (twice.twice (f.f) . (f.f))
                                  ==> (twice (f.f).(f.f) . (f.f).(f.f))
                                  ==> ((f.f).(f.f).(f.f).(f.f) . (f.f).(f.f).(f.f).(f.f))