• ベストアンサー

schemeのプログラミング

http://codepad.org/arrsvMiU 上記のページに書かれているschemeのコードなのですが、 letとset!を使わないで同じ動作をするプログラムを書くことは出来るでしょうか? 同じ動作で上二つの関数を使わなければ、中身がガラッと変わっても構いません。 どなたかお願いします このプログラム自体は与えられた式の変数に対して、それぞれのレキシカルアドレス、ポジションを求めてそれを加えて式を返す というものです。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

;;; 最近のSchemeじゃ推奨されないけど、letrecが嫌だ、と言う場合はinternal defineを使うのがセオリー。 ;;; 手続き内に手続きをぶち込んで外部から保護したレキシカル環境を作るのがポイント。 ;;; Common Lispと違ってSchemeだと名前空間の制限が(比較的)厳しいので、名前を保護出来るところはした方が良いです。 (define (make-frame depth lst)  (define (loop ls0 ls1 n)   (if (null? ls0)     (reverse ls1)     (loop (cdr ls0)        (cons         (cons (car ls0)            (cons depth (+ n 1)))         ls1)        (+ n 1))))  (loop lst '() -1)) ;;; let <-> lamda式の変換は覚えておきましょう。letはlambda式の糖衣構文なんで、letは必ずlambda式に置き換え可能です。 ;;; 基本的には (let ((x v)) 本体) は ((lambda (x) 本体) v) に機械的に置き換えられます。 ;;; 理論的にはLisp系言語は内部で実際にこの処理を行って(いるものとされて)います。 (define (format-variable v depth frames)  ((lambda (result-variable-list)    (if (null? result-variable-list)      v      ((lambda (var)       (list (var-name var) ': (- depth (var-depth var)) (var-num var)))      (caar result-variable-list))))   (filter (lambda (item) (not (null? item)))       (map (lambda (frame)          (filter (lambda (var) (eq? v (var-name var)))              frame))         frames))))

janjan2224
質問者

お礼

わざわざ新たな回答ありがとうございます。 let<->lambdaの変換は自分でも出来るようにがんばります。 おかげで解くことが出来そうです

その他の回答 (1)

回答No.1

;;; あくまで該当箇所はmake-frame一箇所だけ。 ;;; letを使わない、と言う条件をマトモに受けると、例えば以下のような感じ。 (define (make-frame depth lst)  (letrec ((iter (lambda (ls0 ls1 n)           (if (null? ls0)             (reverse ls1)             (iter (cdr ls0)                (cons                 (cons (car ls0)                 (cons depth (+ n 1)))                ls1)                (+ n 1))))))   (iter lst '() -1)))

janjan2224
質問者

お礼

回答ありがとうございます。 お答えしてもらったのに申し訳ないのですが、 letrecも使わないで書くことは出来ないのでしょうか? またformat-variableでもletが使われいると思うのですが、そちらもどうにかなりませんでしょうか?

関連するQ&A

  • scheme の lambda のはたらき

    scheme で lambda の次に,カッコなしの文字列がくる文は,どのようにはたらくのでしょうか. 例えば, ((lambda x x) 3) ; => 3 ((lambda x x) 3 4) ; => (3 4) のような式と結果は,なぜこのようになるのでしょうか. もともと, http://rosettacode.org/wiki/Matrix_multiplication にある 65 Scheme のコードを理解したい,というのが動機です. lambda の上のような用法について,web上で分かりやすい説明がありましたら, 合わせて教えていただけましたら幸いです. よろしくお願いいたします.

  • Schemeについての問題

    今大学でSchemeについて学んでいるのですが、そこで出た問題がわからなくて困っています。 よければ、教えていただけないでしょうか。 問題は以下の通りです。 問1 次に示すScheme プログラムについて以下の問に答えよ。 (define (subtree? t1 t2) (cond ((atom? t1) (eq? t1 t2)) (#t (cond ((atom? t2) #f) (#t (or (and (subtree? (car t1) (car t2)) (subtree? (cdr t1) (cdr t2))) (or (subtree? t1 (car t2)) (subtree? t1 (cdr t2))))))))) 関数subtree?は二つのS 式(S 表現) t1, t2 を入力とし、真偽値(#t あるいは #f) を返す関数である。 関数subtree?が真(#t) を返すための必要十分条件は何であるか答えよ。 また、関数subtree?が実際そのような関数であることをS 式に関する帰納法を用いた議論によって示せ。 考えたのですが、わからなくて。こんな質問してしまって申し訳ないです。 よければよろしくお願いしますm(_ _)m

  • プログラミング言語の説明

    大学4年の者です.  プログラミング言語で作成したアプリケーションについての論文を作成しているのですが,プログラムの説明(変数や関数)についてはどのように説明を行えばよいでしょうか コメントを記載したソースコードを張り付ける方法も考えましたが,それだと文ではないだろうと考え辞めました. 関数の処理はかきつらねるべきなのか段落に番号を振ってわけるのかなど,同期にプログラミング言語を使った論文を書いている人がいないので困っています.

  • C言語に関することについて教えてください

    学校の問題集にでてきた問題がわかりません、どうか教えてください 1 プログラムの役割、必要性について説明せよ 2 プログラムにおける変数と定数の役割を説明せよ。また、ローカル変数の有効な範囲について説明せよ。 3 C言語で使う変数が他について、宣言子と、printf関数、scanf関数それぞれにおいて対応する書式指定子を対応表にせよ。また、変数名を決める際に守るべき文法上の規則と、プログラマとして配慮すべき事項を説明せよ。 4 配列について、その役割と定義方法を説明せよ。 5 コンピュータにおける文字処理に必須なアスキーコードについて説明せよ。 6 C言語における文字列について、文字列定数、文字列変数を説明せよ。 7 C言語における繰り返し処理の文法(for,while,do~while)を、プログラムコード列を示して説明せよ。 8 C言語における条件判断の文法(if,else,else if)を、プログラム列を示して説明せよ。 9 繰り返し、条件判断において利用する論理式(等値演算子、関係演算子、論理演算子等で記迷する式)について、その記迷の方法を論理和、論理積も含めて説明せよ。 10 変数のアドレスについて説明せよ。また、ポインタについて、アドレスとの関連性を踏まえて、その役割と定義方法を説明し、具体的な使い方のプログラムコード例を示せ。 11 ポインタと配列の関係について、ポインタによる配列操作を列に説明せよ。 12 関数について、その役割と定義方法について説明せよ(戻りがた、関数名、引数リスト)。また、自作関数をそれらを利用するmain関数のプログラムコード例を示せ。 13 scanf関数の戻り値について、その内容を説明して、どのような際に利用すると便利か、プログラムコード例を示して説明せよ。 14 引数にポインタを利用する関数のプログラムコード例を示して、ポインタの必要性、重要性を説明せよ。 15 構造体について、その役割と定義方法を説明し、具体的な使い方のプログラムコード例を示せ。 16 ファイルポインタについて説明し、ファイル入出力の方法についてプログラムコード例を示して説明せよ。

  • 長編プログラミングの設計のコツ

    都合の良い話ですが、書籍や時間の取られる専門的な勉強を避け、 出来るだけ簡単にプログラムを設計するコツを知りたいのです。 今までは、どのような言語でも、数百行のコードを思いつくままに、 浮かんだアイデアを取り入れながら、コーディングして来ましたが うまく行っていました。 数ヶ月前に、1万行程度のコードを書いていて、 コードを見やすくするために、汎用処理を別ファイルにまとめたり、 関数化したり、オブジェクトにしたりして、20個以上のファイルに 分割されたコードが出来ました。 ブロック単位での挙動はテスト済みだったのですが、いざ完成直前に バグが頻発しました。 デバッグに入り、1連の処理が複数ファイルに分散されている事や 複数の関数から参照される処理が多々存在するなど、修正した部分 が新しいバグを引き起こすような事態になり。 コーディングよりもバグを取り除く事に遥かに時間が掛かり過ぎて、 結局、1からつくり直す事にしました。 前回の失敗を無くすため、なるべく各関数の依存度を下げ、カプセル化 やコメントをまめに書く事にに勤めました。 すると、今度はコードが3割程度長くなった挙句、1つのファイルの コードが長くなり、頓雑な、依存度を下げるために使った処理や変数の 数も倍以上に増えて、思いつくまま流れるようなコーディングが出来ず、 結局毎日作業開始時には、長々としたコメントを読むことから始めなく てはいけません。 一日3時間位しか取れない作業時間のうち、その作業に1時間は取られて はかどらず、挫折してます。 是非、主観的なご意見で構いませんので、お勧めの方法があれば アドバイス頂けませんでしょうか? ○参考にしてください。 デバッグの際に複数ファイルに渡った変数や処理の参照が作業を 困難にしているのは解っているが結局出来上がるとそうなってしまう か冗長なコードになってしまう。 記憶に頼る管理は極端に苦手(一日たつと、何を書いていたのか解らず、コード全体を読み直す事がしばしば)。 ファイル構造を始めに決めて処理の流れをある程度書き出して始めた たが、実際にコーディングを始めると思いつくままにコーディングが できす、構造管理に気を取られ頭が真っ白になる。 変数をハッシュなどでまとめて解りやすくしたつもりが、意外と読みにくい。 今までは、デバッグに関しては、記述ミスや、1つずつの変数や関数の 動作をトレースする事で事足りたので、今回も、それ以外のデバッグ 方法は取っていない。

  • 至急!助けて下さい。プログラミングJava

    明日までの大学の課題が、わかりません。 どなたか教えてください。書き方が、わかりません。言語はJavaです。 よろしくお願い申し上げます。 1.条件分岐 整数d,xをキーボードから入力させ、 dとzの差の大きさ(絶対値)を計算し、結果を表示するプログラムを作りなさい。 2.繰り返し 整数qcをキーボードから入力させ、1からqcまでの整数を全て表示させるプログラムを作りなさい 3.式 式y=xの二乗+6x+10の値を、x=13から21まで、一つづつ変化させた時のyの値を表示しなさい。 4.和 1から58までの和1+2+3+….+58をプログラムを作って求めなさい。 5.乱数 乱数関数rnd()を使って、変数wgに0~383までの適当な数値を代入し、その結果を出力しなさい。 6.円を描く for文を使って、適当な位置に半径17の赤い円を、87個だけ描きなさい。 7.余り 変数qeに整数を入力させ、その変数qeが6で割り切れたら「割り切れる」と表示し、それ以外は「割り切れない」と表示するプログラムを作りなさい。 *ヒント %演算子で割った余りが求められる。 例えば、5%3は2となる。 8.break文 変数bjに0から1000までの乱数を作っては代入することを繰り返し、bjの値が900以上になったら繰り返しを止めて、bjの値を出力するプログラムを作りなさい。 9.カウント 1から1076までの整数の中で、8で割り切れる数がいくつあるかカウントしてその数を表示しなさい。 以上です。 どうかお助け下さいm(__)m

  • javascriptのレキシカルスコープについて

    JSのレキシカルスコープがわかりません。 JSだと、一番外側のスコープで var str = "一番外側のスコープ"; とすると それ以降、ユーザー定義関数の中の、いわゆる関数スコープ内でも var str; と関数内で再定義しない限り、str = "一番外側のスコープ";を つかいまわすことになりますよね? 一度、関数内で、値を変更すると親スコープでもその変更が生きたままになると思います。 var str ="一番外側のスコープ"; function test(){ alert(str); str ="値の変更"; } alert(str) // 関数内で値をかえたけど、それが親スコープにも反映されてしまう。 このことがレキシカルスコープでしょうか? ただ、どこかのサイトで var num = 100; function makefunc() { return function() { alert(num); } } function callfunc() { var num = 50; var func = makefunc(); func(); }; callfunc(); でmakefunc()関数を呼び出した際の 関数内のnumという変数の値が100になるというのです。 実際、実行するとその通りなのですが、 var num = 50; という宣言は、callfunc() という関数の関数スコープ(ローカルスコープ) というのは理解しています。 でその中のいわゆる内部関数というのでしょうか? var func = makefunc(); func(); を実行した際の 変数numというスコープが 一番最初に宣言した  var num = 100; という値をさすというのです。(※そのサイトではこれをレキシカルスコープと呼んでいました) いったどういう動作がレキシカルスコープなのでしょうか? 他にも、クロージャともごっちゃになっております。 識者の方ご教授ください。 参考元はここです http://garden-place.jp/tech/javascript/scope-chain.html

  • (JavaScript)変数や文字列難しい

    JavaScript 第1問目 // [変数 - 右辺が変数を使った式1] // ---------------------------------------- // 変数sに、変数piの値に変数rの値を2回掛け合わせた値を代入してください let pi = 3.14; let r = 5; ×let s = ; console.log("円の面積は" + s); ※×は間違い。 第2問目 // ---------------------------------------- // [文字列 - 大文字に変換1] // ---------------------------------------- // 変数cの文字を大文字に変換して出力してください let c = "p"; ×console.log(toUpperCase+()); ※×は間違い。 第1問目 ×let s = ;のところですが、let s = (3.14*5)+(3.14*5);でも間違いです。変数sに、変数piの値に変数rの値を2回掛け合わせた値の計算方法やコードは何でしょうか? 第2問目 ×console.log(toUpperCase+());のところですが、console.log(toUpperCase+("p"));やconsole.log(toUpperCase+("c"))は違います。console.log{toUpperCase+}も違います。大文字に変換するコードは何でしょうか?

  • [LISPプログラミング] ラムダ計算 - 置換(substitution)

    LISPプログラミングの課題についての質問(その2)です. 以下に,課題,課題を解くのに必要な知識,試作したプログラム,質問を,この順に載せます.長くなりますがご了承ください.なお,この質問に答えられる方(LISPとラムダ計算の両方の知識がある方)は, http://okwave.jp/qa5152352.html の質問にもお答えいただけると幸いです. 【課題】λ式のリダクションに関する以下の関数を作成せよ. 2. [lexp1/x]lexp2 を表現する関数 substitution   (substitution 'x lexp1 lexp2) 【課題で扱うλ式,ラムダ計算(抜粋)】 A. λ式のシンタックス(を BNF で記述したもの)は以下のとおりである.   <λ-expression> ::= <variable> | <application> | <abstraction>   <application> ::= (<λ-expression>)<λ-expression>   <abstraction> ::= λ<variable>.<λ-expression>   以下,変数(variable)を小文字 x,y,z,... で,任意のλ式を大文字 P,Q,R,... で表す. B. λ式 P と Q が文字まで含めてまったく同じであるとき,P と Q が等しいといい, P≡Q と記す.また,等しくないときは P≡/≡Q と記す. C. 自由変数集合   λ式 E の自由変数の集合を φ(E) と記す.   (1) c が定数ならば,φ(c)={}   (2) 任意の変数 x に対して φ(x)={x}   (3) φ(λx.P)=φ(P)-{x}   (4) φ((P)Q)=φ(P)∪φ(Q) D. λ式 M と N がα合同であることを M=N と記す. E. P 中のすべての自由変数 x を Q で置換(substitution)することを [Q/x]P と記す.   (1) [Q/x]x=Q   (2) x≡/≡y ならば [Q/x]y=y   (3) 任意のλ式 E に対して [Q/x]λx.E=λx.E   (4) x≡/≡y かつ「xがφ(E)に含まれない,または,yがφ(Q)に含まれない」ならば,任意のλ式 E に対して [Q/x]λy.E=λy.[Q/x]E   (5) x≡/≡y かつ x∈φ(E) かつ y∈φ(Q) ならば,任意のλ式 E ,任意の z(ただし,z は x≡/≡z≡/≡y かつ E(Q) の自由変数でも束縛変数でもない)に対して [Q/x]λy.E=λz.[Q/x]{z/y}E   (6) [Q/x](E1)E2=([Q/x]E1)[Q/x]E2 【試作したプログラム】 ; 2. [lexp1/x]lexp2 を表現する関数 substitution ; (substitution 'x lexp1 lexp2) (defun substitution (x lexp1 lexp2)  (if (= (length lexp2) 1)   (if (equal x (car lexp2)) lexp1 lexp2) ; then (1), else (2)   (if (equal 'L (car lexp2))    (if (equal x (second lexp2))     lexp2 ; (3)     ; (4),(5)に対応する処理    )    (if (listp (car lexp2))     (list (list (substitution x lexp1 (car lexp1)))           (substitution x lexp1 (cdr lexp2))) ; (6)     lexp2    )   )  ) ) 【質問】 ラムダ計算というもの自体初耳で,良く分からないまま作成したプログラムです.「E. 置換」の (1),(2),(3),(6) をそのままプログラムにしたつもりです.しかし,自由変数とか束縛変数とかいう概念を無視して作成したので,おそらく誤った動作をすると思います.また,(4),(5)に対応する処理をどのように記述したらよいのかが分かりません.誤りの指摘,アドバイスをお願いします.

  • C言語の演習問題(C言語)について質問です。

    以下のプログラムは数字と演算子を配列に入れているプログラムです。 このプログラムを式を入れて四則演算のみで計算させるプログラムを作成してるのですがご指導お願いできますか? 例:8/3*3enterkey 答え:8 変数の型は変更しないで行うとの指示のことなので、変数は増やしても構いませんが、変えないでお願いします。 http://codepad.org/Iks8CtjT

専門家に質問してみよう