2010-12-30 2 views
5

エクササイズ18.1.12のhtdpから、 "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のコメントがありますか?ありがとうございました。

+0

あなたのための[宗教的な質問](http://en.wikipedia.org/wiki/Socratic_questioning)があります:あなたはなぜ非ローカルバージョンが「おそらくもっと速い」と思いますか?私はあなたの考えを聞いた後、この質問に本当の答えを投稿します。 :-) –

+0

シフクリス、ASS-umptionsに質問してくれてありがとう。私はあなたの洞察力をますます高く評価することを学んでいます。したがって、リストが大きくなると、「ローカル」バージョンは「純粋な」再帰バージョンよりもはるかに高速です。この結論には、20の数値を持つリストのtime関数を呼び出すことで到着し、平均で550xのパフォーマンスの差が見られることに驚いた。私はRacket/Schemeが内部的にどのように不一致を説明するのか分からない。 "ローカル"バージョンを実行すると、ローカル関数 "m"の20バージョンが値を生成していることがわかります。 – Greenhorn

答えて

3

個人的には、これはlocalの重要性の貧弱な例だと私は思っています。あなたはこの質問の重要性を完全に理解しているとは思わないので、私がすることは、あなたの例を見て、最後にあなたに良い例を与えてください。

CONCEPT

まず第一に、(多くとりわけ)、ここで地元のアイデアは、コードのスニペットの意味を明らかにすることです。

はあなたの例を考えてみましょうあなたの例では、あなたが正しいように見えるmと呼ばれる地元の定数を定義します。しかし、mの文字は意味がありませんので、あなたの解決策は不明です。だから、私たちはあなたのソリューションをどのように修正するのでしょうか?

mには、が明らかにという名前で、mの識別名を指定する必要があります。

:だから、私たちは直接まあ (maxi (rest alon))は、単にので m

find-maxに名前を変更することができます今、あなたのコードがどのように見える (rest alon)

の最大数を見つけると言う(maxi (rest alon))

である何を表すかm考慮することから始めます

;; 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に置き換えると、コードがはっきりとわかります!我々はの経験則のままで、定数に意味のある名前をつけてください。さらに明確にするため

MY例

、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の変化を見つける。だから、ここで学ぶ必要があるのは、最初の解決策でコードを少なくしても、にはが記載されていて、簡単に読むことができるということです。それは疑問の全体的な考えであり、それは馬鹿に見えるかもしれませんが、学問の場面で学習のスキームを強調するのは大変なことです。

第1の解決策と第2の解決策の効率については、第2の解決策は明白な理由からはるかに高速です(ラケットが表現を評価する方法を見てから)。

希望これは

+0

明らかに物事を説明する時間をとってくれてありがとう、アドリアン!私はあなたの借金にいる。 – Greenhorn

+0

問題ありません - 喜んで助けてください。 –

3

代わりのlocalを使用することができます、一つは(特に最近のバージョンで)ラケットの内部定義を使用して、同様に行くことができます。例えば

:それは最後のケースになるたび番目のバージョンでそれが二回(maxi (rest alon))を評価し、一方、それは一度だけ再帰あたり(maxi (rest alon))を評価するため

(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))])])) 
+2

内部定義(目的に応じたもの)は教授言語では使用できません。定義がローカルであることを強調するために、「ローカル」を使用しなければならない。 – soegaard

0

ローカルを使用しては道速くここにあります。

ローカルでは結果が保存されるため、同じ作業を2回行わないようにします。

関連する問題