5

私はSchemeが初めてで、条件が真の場合にifステートメントに複数のアクションを実行させようとしています。私は次のようなものを試しました:

(if (char=? (string-ref str loc) #\a)
        ((+ count 1) (+ reference 1))
        ~else action, etc.~

そして、それは私の行動について不平を言います

アプリケーション: 手順ではありません

括弧を削除すると、true 条件のアクションは次のようになります。

(+ count 1) (+ reference 1)

文句を言う

if: 構文が悪い

まったく実行に失敗します。私は何が欠けていますか?

4

3 に答える 3

12

コードには 2 つの問題があります。1 つ目は、ifフォームの結果と代替に複数の式を含めることはできません。そのための2つの可能な解決策-begin複数の式を囲むために(括弧のカップルだけでなく、プロシージャアプリケーション用です)を使用できます。

(if (char=? (string-ref str loc) #\a)
    ; needs an explicit `begin` for more than one expression
    (begin
      (+ count 1)
      (+ reference 1))
    ; needs an explicit `begin` for more than one expression
    (begin
      ~else action, etc~))

...または acondを使用します。これは、暗黙の が既に含まれているため、より優れた代替手段ですbegin

(cond ((char=? (string-ref str loc) #\a)
       ; already includes an implicit `begin`
       (+ count 1)
       (+ reference 1))
      (else
       ; already includes an implicit `begin`
        ~else action, etc~))

2 番目の問題は、より微妙で深刻です。後件部の両方の式が、おそらく期待どおりに動作していません。これ(+ count 1)は、まったく何もしていません。インクリメント後に使用しなかったため、インクリメントされた値は失われます。他のものと同じです: (+ reference 1)、しかし少なくともここでは条件式の結果として値が返されています。インクリメントされた両方の値をプロシージャに渡す必要があります (おそらく再帰の一部として)。

(cond ((char=? (string-ref str loc) #\a)
       ; let's say the procedure is called `loop`
       (loop (+ count 1) (+ reference 1)))
      (else
        ~else action, etc~))

または、インクリメントの結果を変数で直接更新しますが、これは Scheme でソリューションを記述する慣用的な方法ではありません (C、Java などのソリューションのように見えます)。

(cond ((char=? (string-ref str loc) #\a)
       ; here we are mutating in-place the value of the variables
       (set! count (+ count 1))
       (set! reference (+ reference 1)))
      (else
        ~else action, etc~))
于 2013-04-12T10:24:54.967 に答える
0

の 1 つのアームで副作用のある複数のアクションを実行しようとしている場合は、次のようifにそれらを に配置する必要があります。begin

(if (char=? (string-ref str loc) #\a)
    (begin (set! count (+ count 1))
           (set! reference (+ reference 1)))
    ~else action, etc.~

変数を変更する代わりに、一度に 2 つの値を返したい場合は、次のように式を 1 つのオブジェクトに結合する必要があります。

(if (char=? (string-ref str loc) #\a)
    (cons (+ count 1) (+ reference 1)))
    ~else expression~

この場合、カウントと参照を引き出すには、適用する必要があります。carまた、次cdrのように、if実際には複数の値を返すこともできます。

(if (char=? (string-ref str loc) #\a)
    (values (+ count 1) (+ reference 1)))
    ~else expression~

その場合、カウントと参照を引き出すには、if. これを行う 1 つの方法はlet-values、おそらく次のようなものです。

(define count&ref
  (λ (str ch)
    (let loop ([loc 0] [count 0] [reference 0])
      ; whatever other stuff you're doing
      (if (char=? (string-ref str loc) ch)
          (values (+ count 1) (+ reference 1)))
          ~else expression~ )))

(let-values ([(new-count new-ref) (count&ref "some stuff" #\u)])
  ;in here, new-count and new-ref are bound to whatever count&ref returned
  )

一方、countreferenceがループ内で追跡している変数である場合、最も簡単な方法は、次のifように 内でループの次の反復を呼び出すことです。

(let loop ([loc 0] [count 0] [reference 0])
  ; whatever other stuff you're doing
  (if (char=? (string-ref str loc) #\a)
      (loop (+ loc 1) (+ count 1) (+ reference 1))
      ~else expression~ ))
于 2013-04-12T10:48:43.597 に答える
0

を使用beginして、実行する一連の式を 1 つずつグループ化できます。

(if (char=? (string-ref str loc) #\a)
        (begin (+ count 1) (+ reference 1))
        ~else action, etc.~

beginは最後の式の値、つまり のみを返す(+ reference 1)ため、 の値(+ count 1)は使用されません。

于 2013-04-12T05:59:02.120 に答える