質問
私はコンピュータプログラムののの構造と解釈し、次の午前例1.3を解決しようとしたとき、私は私の最初の試みとして、次のコードに到着します:
(define (sumsq a b c)(
(define highest (if (> (if (> a b) a b) (if (> a c) a c)) (if (> a b) a b) (if (> a c) a c)))
(define second_h (if (> (if (> a b) b a) (if (> a c) c a)) (if (> a b) b a) (if (> a c) c a)))
(+ (* highest highest) (* second_h second_h)))
これは働いていませんでしたし、私は解決策を見上げると SICPウィキでそれらを発見しましたA>
;; ex 1.3
;; implemented using only techniques covered to this point
(define (square x) (* x x))
(define (sum-of-squares x y)
(+ (square x) (square y)))
(define (largest-two-of-three x y z)
(if (>= x y)
(sum-of-squares x (if (>= y z) y z))
(sum-of-squares y (if (>= x z) x z))))
の違いは、私が正しい方法で機能するように、私のラインの各々を定義することであるが、変数を定義し、次に正方形を合計する複数のステートメントを使用していたということでした。
は、スキーム1ライナーで機能していますか?それとも私が全部を見逃したのですか?
解決
あなたが書いたもの(マイナス1の余分な括弧)があります:
(define (sumsq a b c)
(define highest
(if (> (if (> a b) a b)
(if (> a c) a c))
(if (> a b) a b)
(if (> a c) a c)))
(define second_h
(if (> (if (> a b) b a)
(if (> a c) c a))
(if (> a b) b a)
(if (> a c) c a)))
(+ (* highest highest) (* second_h second_h)))
彼らのソリューションは、独立した広場や平方和の別の関数にしていますが、私はそれが重要だものだとは思いません。 (+ (* a a) (* b b))
を書いていないの を使用すると、最後に一つの大きな式として関数を書いてみましょうであろう、あなたが計算している2つの値を名前に持つからあなたを停止するが、今心配するより大きなものがあります。
私はあなたが抱えている問題は、あなた(IF ...)の式は簡単に理解することが大きすぎるということだと思います。 (if (> a b) a b)
と(if (> a b) b a)
:何回も現れる二つのパターンがあることに注意してください。これらは、最大と最小の機能なので、それはそのように定義すると便利です。
(define (min a b) (if (< a b) a b))
(define (max a b) (if (< a b) b a))
このように、あなたはあなたのソリューションを書き換えることができるようにます:
(define (sumsq a b c)
(define highest
(if (> (max a b) (max a c))
(max a b)
(max a c)))
(define second_h
(if (> (min a b) (min a c))
(min a b)
(min a c)))
(+ (* highest highest) (* second_h second_h)))
再びそれを簡素化することはできます:
(define (sumsq a b c)
(define highest
(max (max a b) (max a c)))
(define second_h
(max (min a b) (min a c)))
(+ (* highest highest) (* second_h second_h)))
この書き込みがはるかに理由は簡単です注意してください、(max (max a b) (max a c))
は明らかにa
のb
とc
の最大値であり、実際(max (max a b) c)
ように書き換えることができます。 second_h
を見ると、しかし、それが正しいだことは明らかではありません。 a
は、3つの値の最小であると何が起こるのだろうか?
彼らは溶液中で使用するトリックは、最初x
とy
を比較することです。 x < y
場合、その後、あなたはそれがいずれかの最高又は2番目に高いのでy
は、3の最小ではないことを知っています。これら二つの下には、あなたが無視したい3、最小となりますので、使用したいと思うでしょう、他の数は、x
とz
の高いです。ときy < x
ます。
他のヒント
あなたは、適切なインデントと行は、あなたのプログラムの流れの上に概要を取得するために壊し使用する必要があります。あなたの最初の提案は、このように読み込みます:
タグ
(define (sumsq a b c) ((define highest (if (> (if (> a b) a b) (if (> a c) a c)) (if (> a b) a b) (if (> a c) a c))) (define second-h (if (> (if (> a b) b a) (if (> a c) c a)) (if (> a b) b a) (if (> a c) c a))) (+ (* highest highest) (* second-h second-h)))
注目すべき
まず最初:括弧が一致していません。よりクローズドより開かれたものがあります。慎重な検査は、2行目の1つの括弧が間違っていることを示しています。これは、偶然に、何らかの形であなたの最初の行の末尾にぶら下がったものです。私はあなたがこれを評価しようとしたとき、読者は、文の終わりを待っていたとして、何も、起こらなかったことを推測をハザードでしょう。
適切なインデントは非常に重要です。私は例が一般的にこの方法で行われているがSICPが明示的に、それを説明していないと思います。私が見つかりました。ここにのスタイルガイドのます。
第2の観察:あなたは自分自身に多くのことを繰り返します。これらすべてのネストされたif
文では、私はあなたが本当に正しい値を外に出たかどうか本当にわかりません。あなたはこれを大幅に簡略化することができる方法を確認することが分かっソリューションを見ます。
あなたはsubresults名を与えることによって、複雑さを壊すことを試みました。複雑さを壊すことは良いですが、それは名前ではありません結果、その概念に一般的に優れています。あなたは何をすべきかを考え、その後、これらの活動に名前を付けます。これらは機能している、と彼らはあなたが最終的にはほとんど自明であなたの問題を解決するための言語を構成する。
スキームのアイデアの一つは、それぞれ、すべての概念操作のための関数を作成bottom-up programming
です。それは多くの関数型プログラミング言語で推奨されるアプローチです。
このアプローチを使用すると、引数の一つの論理動作を実現する小型の機能の多くで終わります。そのようにあなたのコードははるかにモジュラーとクリーンをされて終わる。
あなたのソリューションは、このフォームを持っていた:(()...定義(...定義))(FUNCのPARAMを定義する)
しかし、このフォームニーズを定義します((FUNCのparam)体を定義する)
ボディは、それが返すものを、それが何をするか...関数の実装です。あなたの体はちょうどより多くの定義、決して何もしていました。あなたのソリューションは、Schemeインタプリタによって受け入れられなかった理由だから、説明します。
質問に答えるために、「スキームの機能をワンライナーですか?」あなたはこのようになります "始まる" フォームを、調査する必要があります(開始(+ 1 1)(+ 2 2))=> 4
あなたはそれが始めるのを見ることができるようには、上記の例では、(1 + 1)の結果はそれの内側のものは、副作用を持っているときだけは本当に理にかなって、道をスローされます。
あなたはスキーム(とりわけせて、ラムダ)の一部が自分の体の周りに暗黙的に開始されますされていることを認識する必要があります。だから、これは有効です。
(let ((x 1))
(+ 1 1)
(+ 2 2))
さえせずに始めます。これは、単純なコードを書くことができます。
あなたがスキームを学び続けて最後に、常にノー開始し、副作用のない何かをする方法を見つけることを試みます。あなたが考えている場合は特に、ほとんどのSchemeの本の最初の数章では、「私は、私はこれをしたい、その変数を設定したい、これは...」あなたはおそらく、プログラミングの古いやり方に閉じ込められ、行っていませんそのスキームの方法。そこにすべての副作用は何も問題はないのですが、それらの大量の使用は、あなたが本当にそれは最高の作品の方法をスキームをプログラミングしていないことを意味します。
運動1.3は、引数として3つの数字を取り、2つのより多くの二乗の和を返すプロシージャを定義するように求められます。これは、内蔵のスキームの手順square
、max
、およびmin
を使用してそのように手順を定義するのは簡単ですが、我々はまだ本の中で、その時点で、これらの手順が発生していないので、私は同様にそれらを定義すると思います。
(define (square x)
(* x x))
(define (max x y)
(if (> x y) x y))
(define (min x y)
(if (< x y) x y))
(define (sum-of-highest-squares x y z)
(+ (square (max x y))
(square (max (min x y) z))))
sum-of-highest-squares
手順は、xとyの最大値(これら二つの最大値は、3つの最も低いことから排除される)、残りの2つのxの(最小の最大の正方形の二乗を加算することにより動作し、 Y、)第一工程から残され、そしてZた方の値になります。
注:これは私のブログの記事からである SICP 1.1演習 - 1.5 に。そこに、他のSICPソリューションの多くに行くことができますリンクがあります。