LoginSignup
0
0

More than 1 year has passed since last update.

[CPS変換]継続ってパイプライン的な何かだなと思ったらなんかわかってきた3

Last updated at Posted at 2023-03-31

ここから先は、独自実装です。何か問題があればコメントお願いします。

まとめ: ret,skip を実装するだけで、パイプラインの中で分岐できます。 お手軽で うれしい!

もっとお手軽にしてみる

前の記事で、pipe、ret、bind、callCCの合わせ技で分岐ができるっていうのはわかりました。でも、もっとお手軽なのがいいな...というわけで、もっと簡単にできないか考えてみました。

const ret = x => 
  k => k(x)

const skip = x => _ =>
  k => k(x) 

値を継続に渡す ret、継続を一個だけ無視してその次の継続に渡す skip を定義してみました。これだけです。pipe/bind/callCCは無しです。
これを使ってフィボナッチ数列を求める関数を書いてみました。

// 使用例:
const fibCPS = n =>
  ( n < 2 ? skip(1) : fibCPS(n - 2) )
  ( a => fibCPS(n - 1)
         ( b => ret(a + b) )
  )

fibCPS(5)(x=>x)  // 8

callCCほど高機能ではないですが、これですむことはかなり多いんじゃないかと思います。

また、skip 単体では継続をひとつ飛ばすことしかできませんが、そこに複数の継続を入れておけば、callCC相当のことができそうです。

前の記事のcallCCの例です。

const g = x => 
  pipe( callCC( exit => pipe( x === 0 ? exit(x) : ret(x) )
                            ( bind( x => ret(x + 1)) )
                            ( bind( x => ret(x + 1)) )
                            ()
              )
      )
      ( bind( x => ret(x + 1)) )
      ( evalCont )
      ()

g(0)  //  1
g(1)  //  4

同じことを skip でやるならこうです。

const g = x =>
  ( x === 0 ? skip(x) : ret(x) )
  ( x => ret(x + 1)
         ( x => ret(x + 1) )
  )
  ( x => ret(x + 1) )
  ( x=>x )

g(0)  //  1
g(1)  //  4

exitが callCC内の継続を無視して、外部のcallCCの継続に渡す、っていう性質と、
skipが 次の継続を無視して、その次の継続に渡す、っていう性質が対応しています。

ちなみに、単にかっこでくくってやるだけで:

const g = x =>
  ( ( x === 0 ? skip(x) : ret(x) )
    ( x => ret(x + 1)
           ( x => ret(x + 1) )
    )
  )
  ( x => ret(x + 1) )
  ( x=>x )

callCC の構造っぽく見せることもできます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0