読者です 読者をやめる 読者になる 読者になる

レガシーコード生産ガイド

私に教えられることなら

Forthでユークリッドの互除法とローカル変数

forth

早速The Art of Computer Programmingを読んでいて、アルゴリズムを試したくなったので自作のForth処理系jf64を使った。自分の庭というカンジで楽しい。

本題だけど、Forthでよくデメリットとして挙げられる(っぽい)のがスタックジャグリングの難しさと保守困難性だ。僕も練習してその場では書けるようになっても、後から読むときの時間は短縮しなさそうと判断して、ローカル変数を多用して避けている。

ただ、実際にやらずに避けるのもな、とも思うので、簡単な例ではローカル変数使用・未使用両方書いて練習してみようと思った。それで後から見返して、やっぱり無理とか、意外と読めるとか判断すればいい。(というかっこいい理由もあるけど、単にスタックジャグリングがパズルみたいで面白いというのもある。)

というわけでユークリッドの互除法の、ローカル変数使用版(どちらもjf64用)

: gcd { m n -- x }
  m n mod { r }
  r 0= if n return then
  n r tail-recur ;

未使用版

: gcd ( m n -- x )
  dup -rot mod
  dup 0= if drop return then
  tail-recur ;

そのときのスタックの状況も書いてみる。

: gcd ( m n -- r )
  dup -rot    ( n m n )
  mod         ( n r )
  dup 0=      ( n r 1or0 )
    if        ( n r )
      drop    ( n )
      return
    then      ( n r )
  tail-recur ;

今はやっぱりローカル変数使用版の方が好きだな。この場合は特にそうだけど、アルゴリズムをそのまま文章で書き下したようになって、書きやすいしわかりやすい。

コメントもつけてみる。

: gcd { m n -- x }
  m n mod { r }         ( mをnで割った余りをrとする )
  r 0= if n return then ( 余りrが0なら、nが最大公約数なので返す )
  n r tail-recur ;      ( そうでなければ、nとrについて再帰する )
広告を非表示にする