5

問題は次のとおりで、http://www.cs.indiana.edu/classes/b551-leak/scheme_practice.htmlにあります。

問題定義: Scheme で提供されている car/cdr 演算子の一般化である関数 cxr を書きます。cxr は、実行される car および cdr 操作のシーケンスを表す "a" と "d" の文字列を取り、そのシーケンスを実行できる関数を返す必要があります。

したがって、(cxr "ad") は関数 cadr と同等です。

    ((cxr "ad") '(i ii iii iv v vi vii))  ==> ii
    (define sixth (cxr "addddd"))
    (sixth '(i ii iii iv v vi vii))         ==> vi

私の試み: string-append を使用して cxr "ad" を文字列 "cadr" に変換しました。[これは簡単です] .. "cadr" と cadr の間をどのようにリンクできますか... string->symbol を試しましたが、出力が引用符で囲まれているため、関数が実行されません。-- 引用符を外す方法はありますか?!

本当の質問: この問題を解決するにはどうすればよいですか?


更新:これらの回答に感謝します。それらはすべて正しいので、質問を投稿する前に実際にこの方法で解決しました。私は主に、入力が (cxr adddd) のときに caddddr を実際に呼び出す方法を探していました... Everbody は caddddr と同じ機能を実行しましたが、実際には cadddr を呼び出しませんでした。

つまり、cadr caddr などと同じネーミングタイプで関数を作る方法です。


更新:(私は解決策を見つけたと思いますが、それは次のとおりです-しかし、以下に示されているように、より長いdでは機能しません):

(define cxr 
(lambda (ad l)
   ( (eval (string->symbol (string-append "c" ad "r")))   l)
)
)
4

4 に答える 4

5

Mimisbrunnr が指摘しているように、ここでの考え方は、文字列を追加してから評価することではありません。1 つには、これは a と d の長いシーケンスでは機能しません。

代わりに、文字列を消費し、文字列を 1 文字ずつ分析して関数を返す関数を作成します。

HtDP の用語では、文字列をリストに変換した後、「a」と「d」のリストに対する構造的再帰としてこれを行うことができます。

これを簡単にするために、"string->list" を使用できます。これは Racket に存在し、r5rs の一部でもあるという漠然とした感覚があります。

于 2012-03-08T04:29:05.877 に答える
3

あなたは尋ねます:「どうすれば「cadr」とcadrをリンクできますか?

まず、文字 #\a を car に、#\d を cdr にリンクできます。

(define (x->cxr x)
  (if (eqv? x #\a) car cdr))

例:

> ((x->cxr #\a) '(foo bar)) 
'foo

次に、 andcadrの構成であるという事実を使用します(cadr is のように.carcdr(compose car cdr)

(define (cxr s)
  (apply compose
         (map x->cxr 
              (string->list s))))
于 2012-03-08T14:34:32.673 に答える
1

これは可能な実装であり、特定の入力に適用される操作のリストのミニインタープリターです。

(define (cxr ops)
  (lambda (input)
    (generate-cxr (reverse (string->list ops)) input)))

(define (generate-cxr ops-list acc)
  (if (null? ops-list)
      acc
      (generate-cxr (cdr ops-list) (operate (car ops-list) acc))))

(define (operate op input)
  (cond ((eqv? op #\a) (car input))
        ((eqv? op #\d) (cdr input))
        (else (error "unknown operation" op))))

問題を 3 つの部分に分けました。

  1. cxr呼び出されると、パラメーターとして受け取った一連の操作に対して入力を処理する関数を返します。操作のリストは、宣言された順序とは逆の順序で処理されることに注意してください。
  2. generate-cxr実行する操作がなくなるまで各操作を順番に処理し、結果を蓄積します
  3. operate適用する操作を決定して実際に実行し、結果を返します

上記の手順は正しい答えを返しますが、演算の構文解析が演算の実行と交互に行われるため、非常に非効率的です。構文解析を実行から分離して、より高速なソリューションを作成することができます。SICPのセクション4.1.7を参照してください。

于 2012-03-08T15:02:42.963 に答える
1

編集:あなたの更新に応じて、次のようなことをしたいと思います:

(eval `(define ,<procedure-to-return-symbol> ,<value>) <environment>)

たとえば、mit-scheme では:

(eval `(define ,(string->symbol "abc") ,(* 2 2)) user-initial-environment)

user-initial-environmentREPL に入力されたときにシンボルがインターンされる環境はどこにありますか。abcこの例では、値 4 に関連付けられたシンボルが返されます。このメソッドを使用すると、プロシージャを使用して名前を作成し、以下のソリューションによって返される値に関連付けることができます。evalおよび mit-scheme 環境の詳細については、こちらを参照してください。 </edit>

EDIT2:明示的な解決策:

(define (cxr x)
  (define (helper xlist arg)
    (cond ((null? xlist) arg)
          ((eq? (car xlist) #\a) (car (helper (cdr xlist) arg)))
          ((eq? (car xlist) #\d) (cdr (helper (cdr xlist) arg)))
          (else (error "INVALID ARGS FOR CXR"))))
  (eval `(define ,(string->symbol (string-append "c" x "r"))
           ,(lambda (arg) (helper (string->list x) arg))) user-initial-environment))

このようにして、任意の深さの「広告」文字列に対して名前付きプロシージャを作成できます。</edit>

carあなたの最初のソリューションは、構成があり、cdrすでに定義されている場合に、せいぜい使用可能です。問題は、リストの car/cdr を任意の深さまで取得するプロシージャを返すプロシージャを探しています。これが私の解決策です:

(define (cxr x)
  (define (helper xlist arg)
    (cond ((null? xlist) arg)
          ((eq? (car xlist) #\a) (car (helper (cdr xlist) arg)))
          ((eq? (car xlist) #\d) (cdr (helper (cdr xlist) arg)))
          (else (error "INVALID ARGS FOR CXR"))))
  (lambda (arg) (helper (string->list x) arg)))

helpera と d のリストを実行し、次の呼び出しの結果に基づいてcarorを呼び出します- の本体を構築します。リストが空の場合、式のパラメーターを返します。フォームには定義で引数が渡されていないため、プロシージャが返されます。 cdrhelperlambdahelperarglambdalambdacxr

于 2012-03-11T21:33:23.670 に答える