combine
は、バイナリ演算子bin
でリストを減らす必要がありますが、述語pred?
に失敗した値を検出した場合はexc
を返し、その値を検出した場合はリストで計算を実行してはなりません。Racketでのcall/ccの面白い動作を説明するには?
これは簡単な問題です。
#lang racket
(define (id x)
x)
(define (const x)
(lambda (_) x))
(define (combine pred? bin zero exc)
(call/cc
(lambda (exit)
(letrec
((f (lambda (xs)
(if (empty? xs)
zero
(if (pred? (first xs))
(exit exc)
(bin (first xs) (f (rest xs))))))))
f))))
(define product
(combine zero?
*
1
0))
(product '(1 2 3 0 4))
コードはほぼ動作しますが、それは非常に微妙な誤差を持っています。
これは、次の例外が発生します:
define-values: assignment disallowed;
cannot re-define a constant
constant: product
それを動作させるのは簡単です。わずかな変更が必要とされている:
(define (combine pred? bin un zero exc)
(lambda (ys)
(call/cc
(lambda (exit)
(letrec
((f (lambda (xs)
(if (empty? xs)
zero
(if (pred? (first xs))
(exit exc)
(bin (first xs) (f (rest xs))))))))
(f ys))))))
私はこの問題は、ラケットは、定義の継続は関数を定義することですが、誰もがより多くの詳細を与えることができることであることを参照してください?たとえば、どのような構文的変換が関与していますか?あなたがここに持っている必要がありますための
これはスキーム自体の面で説明できますか、実装の中で言語を見なければなりませんか? –
@Rdgstv '#lang racket'は標準に準拠していませんが、互換性があるようです(http://www.r6rs.org/final/html/r6rs/r6rs-ZH-14.html#node_idx_352)実行の責任:実装は、の継続が2回以上呼び出されたことを検出しなければなりません。実装がこれを検出した場合、条件タイプ&アサーションで例外を発生させる必要があります。ラケット(実装)は、標準のSchemeレポート言語の多くをサポートしています。私は同じプリミティブとして 'define'と' set! 'を持つ多くの "scheme"実装を見てきました。 –
Sylwester
@Rdgstv 'call/cc'について理解しています。すべての 'call/cc'は、継続を関数として公開することです。多くのSchemeの実装は、とにかくコードをCPSに変えますが、 'call/cc'ではそれをしません。 CPS 'call/cc'はちょうど'(define(call/cc body c)(body(ラムダ(値の実際の継続)(c値)))c)) 'です。 'define 'のような特別な形式はCPSではできません。関数内からトップレベルのバインディングを定義するプリミティブがないからです。 (関数内の 'define'は' letrec'となり、これは私たちが望むものではありません) – Sylwester