6

htdp の演習 18.1.12 で "local" を使用して maxi 関数を書き直しました。

;; maxi : non-empty-lon  ->  number
;; to determine the largest number on alon
(define (maxi alon)
  (cond
    [(empty? (rest alon)) (first alon)]
    [else (local ((define m (maxi (rest alon))))
            (cond
              [(> (first alon) m) (first alon)]
              [(> m (first (rest alon))) m]
              [else (first (rest alon))]))]))

本のバージョンはより短く、より明確で、おそらくより高速であるように見えるので、なぜ「実生活」でこれを行うのかわかりません。

(define (maxi alon)
  (cond
    [(empty? (rest alon)) (first alon)]
    [else (cond
        [(> (first alon) (maxi (rest alon))) (first alon)]
        [else (maxi (rest alon))])]))

それは純粋に教育的な演習を意図したものでしたか? 経験豊富なSchemerが上記のコードについてコメントできますか? ありがとうございました。

4

3 に答える 3

4

個人的には、これは重要性の悪い例だと思いますしlocal、質問の重要性を完全に理解していないと思います。そのため、私が行うことは、注意すべき概念を調べてから、あなたの例を調べて、最後により良い例を挙げてください。

概念

まず、ここでのローカルの考え方は (他の多くのことの中でも) 、コードのスニペットの意味を明確にすることです。

あなたの例

あなたの例を考えてみましょmう。正しいと思われるローカル定数を定義します。ただし、手紙mには重要な意味がないため、解決策が不明確に見えます。では、どのように解決策を修正できますか?

何を表すのかを明確に識別mできる名前を付ける必要があります。そこで、何が何を表しているかを直接考えることから始めます。mm(maxi (rest alon))

簡単(maxi (rest alon))に言うと、最大数を見つける(rest alon)

だから、名前を変更しましょmfind-max

コードは次のようになります。

;; maxi : non-empty-lon  ->  number
;; to determine the largest number on alon
(define (maxi alon)
  (cond
    [(empty? (rest alon)) (first alon)]
    [else (local ((define find-max (maxi (rest alon))))
            (cond
              [(> (first alon) find-max) (first alon)]
              [(> find-max (first (rest alon))) find-max]
              [else (first (rest alon))]))]))

に置き換えるmfind-max、コードがより明確になります。経験則を残して、定数に意味のある名前を付けます。

私の例

さらに明確にするために、2 つの点を消費し、2 つの点を結ぶことによって作成される線分の勾配を生成する関数を考えてみましょう。最初のアプローチは次のとおりです。

;;where x1,y1 belong to point 1 and x2,y2 belong to point 2
(define (find-slope x1 y1 x2 y2)
  (sqrt (+ (sqr (- x2 x1))) (sqr (- y2 y1))))

しかし、次を使用してより明確にすることができますlocal

(define (find-slope x1 y1 x2 y2)
  (local
    [(define delta-x (- x2 x1))
     (define delta-y (- y2 y1))]
    (sqrt (+ (sqr delta-x)) (sqr delta-y))))

関数がその部分で何をするかをデルタがどのように説明しているかに注目してください。x または y の変化を見つけます。したがって、ここで学ぶ必要があるのは、最初のソリューションは使用するコードが少ないかもしれませんが、2 番目のソリューション何をしているかを説明しており、簡単に読むことができるということです。それが質問の全体的な考え方であり、ばかげているように見えるかもしれませんが、学術的な設定でスキームを学ぶときに強調する傾向がある慣習です.

1 番目と 2 番目のソリューションの効率に関しては、(Racket がどのように式を評価するかを見た後で) 明らかな理由で 2 番目のソリューションの方がはるかに高速であることは間違いありませんが、それは質問の主な目的ではありませんでした。

お役に立てれば

于 2011-01-02T07:04:40.820 に答える
4

を使用する代わりに、localRacket の内部定義を使用することもできます (特に最近のバージョンでは)。

例えば:

(define (maxi alon)
  (cond
    [(empty? (rest alon)) (first alon)]
    [else (define m (maxi (rest alon)))        ; here is an internal define
          (cond
            [(> (first alon) m) (first alon)]
            [(> m (first (rest alon))) m]
            [else (first (rest alon))])]))
于 2011-09-25T04:36:39.587 に答える
2

(maxi (rest alon))local を使用すると、再帰ごとに 1 回しか評価されないため、ここでははるかに高速ですが、2 番目のバージョンで(maxi (rest alon))は、最後のケースに到達するたびに 2 回評価されます。

  (cond
    [(> (first alon) (maxi (rest alon))) (first alon)]
    [else (maxi (rest alon))])

Local は結果を保存するので、同じ作業を 2 回行う必要はありません。local で out を持ち上げる(maxi (rest alon))と、else のケースではないことに注意してください。

(local ((define m (maxi (rest alon))))
  (cond
    [(> (first alon) m) (first alon)]
    [else m]))
于 2015-11-30T22:08:03.517 に答える