- ベストアンサー
Schemeのlambdaを使うべきか使わないべきか
- Schemeを学んでいる中で、lambdaの概念について理解できていないことに悩んでいます。
- 末尾再帰法を使ってリストの中から最小の数を表示する関数を書きましたが、無駄に長くなってしまっている気がします。
- lambdaを使わずに短く書くことはできるのでしょうか?適切にlambdaを使う判断基準が分かりません。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
>そんなんでいいんですか? いいんです(笑)。少なくとも今のところは(笑)。 >最近Schemeを習い始めた って言うので、今のとこはそんな感じで十分ですよ。 >ではlambdaはなんのためにschemeにあるんですか? 「クロージャを表現するため」です。 とか言われても最初は何の事やらサッパリです(笑)。僕もそうでした。 例えば、良く使われる一番シンプルな例としてはアキュムレータ(累積器)があります。 (define (addn n) (lambda (x) (+ x n))) これは例えばこんな風に使います。 > ((addn 1) 1) 2 > ((addn 1) 2) 3 > ((addn 2) 3) 5 > これ何やってるのか、と言うと初見じゃピンと来ないでしょ? Schemeの実行形式が (手続き 引数) だとすると、上の形式で見るとどうも括弧が多く見える。「手続きの位置」にあるモノがまた括弧に包まれて変ですよね。何じゃこりゃ、と。 そして、リストの第一要素が「手続き」ってのはこれはSchemeにおいては基本的な約束事です。とすると(addn 引数)ってのも「これ全体で」手続きじゃないとならない。 その通りなんです。このアキュムレータは手続きなんですけど、返り値も手続きなんです。「手続きを返す手続き」になってる。これは普通の言語ではちょっとあり得ない形式ですよね(最近のSchemeなんかに影響を受けた新しい言語では見られる機能になってきましたが)。 実際、(addn 引数)の実行形式で「何を返すか」見てみますか。 > (addn 1) #<procedure> > (addn 2) #<procedure> > (addn 3) #<procedure> > #<procedure>って返って来てますね。これは(中身は表示出来ないけど)「手続きを返しましたよ」と言う意味です。 これをやってるのが「クロージャ」で、lambda式がやってる事(と言うか、lambda式「自体」が返り値になっている)なんです。 さて、例えば数学では、 I = 3 と言う書き方はオーケーですよね。これは変数なんで構わない。 では、 I = ∫x dx はどうか、って言われればこれもオーケーですよね。別に構わない。右辺が関数だろうと基本的にはオーケーなんですよ。数学の先生も恐らくケチを付けないでしょう。 ところが、古典的な高級プログラミング言語では、 i = 3 とか変数定義はオーケーなんですけど、 i = sin(x) みたいなのは「ダメ」なんです。変数と関数ってのは表記上、一緒に出来ない(上の例だとsinのxに「何らかの数を与えた状態」だとオーケーではあるんですが)。 割に「紙に書く分」にはオーケーな約束事がプログラミング言語では「ダメ」って言われる事が多いんです(少なくとも古典的な文脈では)。 Schemeの場合、この「境界線」を取っ払って、数学のように、「何かを名づける」(Schemeでは「束縛」と呼びますが)行為を「統一的に扱おう」と言う狙いが一つあったんです。 特殊形式defineは (define シンボル 何とやら) で、シンボルと「何とやら」を結びつけます。 普通のプログラミング言語で考えると「何とやら」ってのは例えば数であるとか、あるいは文字列であるとか、とにかく「変わってはいけないもの」が来ます。 反面、Schemeでは、この「何とやら」は基本的に任意で構わない、と言う設計を持ち出したんですね。この「任意」部分に持ってこれるのが実はlambda式で、こう言う感じで結びつけられます。 (define シンボル lambda式) つまり、この時点で、「シンボルと変数が結びつけられる」と言うのと「シンボルと手続きが結びつけられる」と言うのを統一的に扱えるようになった。 Scheme発表当時はこれは結構衝撃的で、この「シンプルさ」に多くの人がショックを受けた模様です。言い換えると、Schemeでは当時のプログラミング言語では普通だった「関数定義」と言う様式を持ってない、って言い方が出来るわけです。ああ、こりゃビックリだ(笑)。 まあ、実用上、この設計が「是」なのか?と言うと、実は色々議論があるんですけど(笑)、少なくともSchemeの場合、このlambda式、と言う形式を中心にして、色んなコンピュータ科学/プログラミング上の「メンド臭い様式」をもっとシンプルに抽象化していこう、とした野心的な言語なのです。 とまあ、こんな説明でよろしいでしょうか?
その他の回答 (2)
- cametan_42
- ベストアンサー率62% (162/261)
うん、そうですね。 提示されたコードのままじゃ上手く動かないですね。 #1氏の仰ってる通りです。 >lambdaを使うべきなのか使わないべきなのかの判断がうまくできません。 まあ、この時点で言える事は「色々やってみりゃエエんちゃうの?」ですけど(笑)。 最終的に「どっちのスタイルに統一するべきか」ってのは個人の好みですけどね。原則、手続き定義に於いては (define 名前 (ラムダ式)) ってのと (define (実行形式) 本体) ってのは丸っきり同じ意味なんで。 ただ、後者の方が「記述が短い」んで一般的には好まれるのかな?ただ、Schemeの「形式」にこだわる人は前者を愛用する、と。 どっちでもエエです(笑)。別に誰にも文句言われません。 ですんで、練習で色々書いていって、「あ、俺こっちの方が好きだな」って時にどっちかにスタイルを統一すれば良いでしょう。
補足
そんなんでいいんですか? ではlambdaはなんのためにschemeにあるんですか?
- Tacosan
- ベストアンサー率23% (3656/15482)
なんというかいろいろアレだと思う. まず, small の定義で if にかっこがないのはおかしい. あと, small2 に渡す「0」の根拠ってなんだ. 次に small2 だけど, small と違い lambda を使って定義しているのはなぜ? ついでにいうと head が束縛されずに使われてるんだけど, それでいいの? 一般論的には, define で束縛する値が lambda なら lambda を使う必要はないはず. もちろん使ってもかまわないけど, この例みたいに使ったり使わなかったりだと混乱させるだけなのでどちらかに統一すべきだと思う.
お礼
よく分かりました。ありがとうございます。