見出し画像

Retro-gaming and so on

RE: プログラミング学習日記 2024/04/12〜

龍虎氏の記事に対するコメント。
今回はRustの重要な性質から見てみよう。

一般的に、C言語系のプログラミング言語では{...}と言う表現はスコープを引き連れたブロックを意味する。
ところで、C言語で次のようなプログラムを書くとしよう。



一見良さそうに見えるが、コンパイルエラーが出る。
C言語ではブロックは単独では存在出来ず、あくまで他の構文(関数定義とか条件分岐とか)の「要素」としての機能しかない事が伺える(※1)。
一方、Rustでは次のような記述は許される。



ここがRustとC言語が決定的に違う部分の一つだ。Rustではブロックは単独で存在出来る
さて、確かに「どっちが正しいか?」と言う問いは無意味と言えば無意味だが、Racketを初めとするLisp観点だとどうだろうか?圧倒的にRustの方が正しく思えるんじゃないか。
Racketでは次のように書くのは許容される、からだ。

(define (main)
 (let ((z (let ((x 1) (y 2))
     (+ x y))))
  (println z)))

こう書きたいかどうかはさておき、だ(※2)。
そう、Rustの{...}はCのそれとは全く違う。むしろRacketの(begin ...)に近い、んだ(※3)。
Rustの{...}は単独で存在出来、「実行可能だ」と言う事を覚えておこう。



ちなみに、これはRacketに直訳すれば以下のようになるだろう(※4)。

(define (main)
 (displayln "Guess the number")
 (let ((secret-number (random 1 101)))
  (call/cc
   (lambda (break)
    (let loop ()
     (displayln "Please input your guess.")
     (let ((guess (read-line)))
      (let ((guess
         (cond ((string->number (string-trim guess)) => (lambda (num)
                              num))
          (else (loop)))))
       (printf "You guessed: ~a~%" guess)
       (cond ((< guess secret-number) (displayln "Too small!"))
          ((> guess secret-number) (displayln "Too big!"))
          (else (displayln "You win!")
            (break)))
       (loop))))))))

Rustのmatchはパターンマッチ、と言いながらRacketのmatchとはちと毛色が違って、Racketのcondが混ざってるような機能だ、って事が分かる。
同様に、変数に結果が代入出来るトコを見ても、Pythonのmatch文と違い、match式である事が分かる(式は返り値がある)。
また、match式とOrderingの組み合わせも強力で、明らかにパターンマッチ以上の事をやってのけてる(結果、与えられた関数を使って高階関数的に真偽値判定をしている)。
Racketもマクロを駆使すれば似たような事は出来るだろうが、「マクロを書く」方がメンドイかもしんない(笑)。

※1: C言語の仕様上、これは「許される」のでは?と思ったが許されなかった(笑)。
仕様的には{...}は単独でも存在出来そうに書いてて、構文「要素」ではなく、構文の一つとなってるようで、「誰もこう書かないけど実は書ける?」とか思ったがやっぱダメだ、って結果にガッカリしてる(笑)。

※2: 通常はlet*を使う局面となる。

※3: Lispのletは理論的にはラムダ式の構文糖衣だ、と言う事を思い出そう。そしてPythonのラムダ式と違って、Racketのラムダ式には「暗黙のbegin」が含まれる。

※4: 初心者向けのベタ書きコードだ。
しかし、本来ならやはりRead-Eval-Print Loop構造で書くべきだろう。
  • Xでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

最近の「RE: プログラミング学習日記」カテゴリーもっと見る

最近の記事
バックナンバー
人気記事