Устранение неполадок / визуализация потоков SICP Программа чисел Хемминга - PullRequest
2 голосов
/ 11 апреля 2019

Я в основном застрял на 3,56 в SICP.Проблема выглядит так:

Упражнение 3.56.Известная проблема, впервые поставленная Р. Хэммингом, состоит в том, чтобы перечислять в порядке возрастания без повторений все натуральные числа без простых факторов, кроме 2, 3 или 5. Один из очевидных способов сделать это - просто проверить каждое целое числов свою очередь, чтобы увидеть, есть ли у него какие-либо факторы, кроме 2, 3 и 5. Но это очень неэффективно, поскольку, поскольку целые числа становятся больше, все меньше и меньше из них соответствуют требованию.В качестве альтернативы, давайте назовем требуемый поток чисел S и обратим внимание на следующие факты:

  • S начинается с 1.
    • Элементы (scale-stream S 2)) также являются элементами S.
    • То же самое верно для (масштабный поток S 3) и (масштабный поток 5 S).
    • Это все элементы S.

Теперь все, что нам нужно сделать, это объединить элементы из этих источников.Для этого мы определяем процедуру слияния, которая объединяет два упорядоченных потока в один упорядоченный поток результатов, исключая повторения:

(define (merge s1 s2)
   (cond ((stream-null? s1) s2)
         ((stream-null? s2) s1)
         (else
          (let ((s1car (stream-car s1))
                (s2car (stream-car s2)))
            (cond ((< s1car s2car)
                   (cons-stream s1car (merge (stream-cdr s1) s2)))
                  ((> s1car s2car)
                   (cons-stream s2car (merge s1 (stream-cdr s2))))
                  (else
                   (cons-stream s1car
                                (merge (stream-cdr s1)
                                       (stream-cdr s2)))))))))

Затем требуемый поток может быть создан с помощью слияния следующим образом:

(define S (cons-stream 1 (merge <??> <??>)))

Заполните пропущенные выражения в местах, отмеченных выше.

До этой конкретной проблемы я мог визуализировать и понимать эти неявные определения потоков с помощью обработки сигналовБлок-схема с исходным потоком, возвращаемым обратно в процедуру.

Но я в основном столкнулся с этой конкретной проблемой, я искал решение, но считаю, что невозможно представить, какрешение будет работать в моей голове / бумаге.

Есть ли хитрость для понимания и поиска решений для такого рода проблем?

Это решение, которое работает:

(define S 
  (cons-stream 1 (merge (scale-stream S 2)
                        (merge (scale-stream S 3)
                               (scale-stream S 5)))))

Заранее спасибо.

Ответы [ 2 ]

2 голосов
/ 23 апреля 2019

Что касается правильного присвоения имени, merge не должен удалять дубликаты, так как его имя предполагает, что он является частью mergesort, который должен их сохранять. Union является лучшим именем для такой операции, которая видит множества, представленные (здесь) путем увеличения списков уникальных чисел, ограничение, которое следует сохранить, удаляя дубликаты, которые могут быть получены только из обоих ее аргументов .

Возвращаясь к самой проблеме, давайте напишем ее символически как

S<sub>235</sub> = {1} &cup; 2*S<sub>235</sub> &cup; 3*S<sub>235</sub> &cup; 5*S<sub>235</sub>

Преждевременная реализация - мать всего зла! (подождите, что?) Мы даже не будем пытаться установить, как именно эти 1013 * выполняют свою работу, даже в каком порядке. Или даже сколько терминов есть:

S<sub>23</sub> = {1} &cup; 2*S<sub>23</sub> &cup; 3*S<sub>23</sub>

или даже

S<sub>2</sub> = {1} &cup; 2*S<sub>2</sub>

Теперь это выглядит достаточно просто. Мы можем даже искусственно реализовать объединение A и B здесь просто, сначала взяв все элементы A, а затем - B. И здесь все будет работать нормально, потому что в этом левом входе есть только один элемент:

 {1} ----∪-->--->--S₂--.--->S₂
        /               \        
        \______*2_______/        
          ---<----<---         

Как это работает? 1 входит в сумматор , выходит из него первым, безоговорочно (Обратите внимание, это обнаруженное требование важно, поскольку если пришлось проверить оба из его аргументов сразу же мы получим бесконечный цикл, черная дыра в Арскоте Хаскелла), разделенный на две части с помощью . сплиттера , а затем первой копии 1 продолжается до выходной точки, в то время как вторая копия 1 возвращается назад через множитель *2, результирующий 2 вводит обратно на этот раз справа, без сопротивления с помощью чего-либо слева (которое в настоящее время уже пусто) и продолжается таким же образом, поэтому 2 переходит к выходной точке, затем 4, затем 8 и т. д. и т. д.

Другими словами, S₂ содержит все элементы {1}; плюс все элементы {1}, которые один раз прошли через множитель *2; и дважды; и три раза; и так далее и тому подобное - все полномочия 2 в порядке возрастания:

S<sub>2</sub> = {1} &cup; 2*{1} &cup; 2*2*{1}                ;; == {1, 2, 4, 8, 16, 32, ...}
                 &cup; 2*2*2*{1}
                 &cup; 2*2*2*2*{1}
                 &cup; ..........

Два S₂ на диаграмме одинаковы, потому что то, что мы выкачиваем из него в точке разделения, не влияет на это.

Разве это не было весело?

Так как же нам добавить к нему кратные 3? Один из способов сделать это -

S<sub>23</sub> = S<sub>2</sub> &cup; 3*S<sub>23</sub>

 {1} ----∪-->--->--S₂--.---S₂----∪-->--->--S₂₃--.--->S₂₃
        /               \       /                \        
        \______*2_______/       \______*3________/        
          ---<----<---            ---<----<---         

Здесь 1 из S₂ входит во второй сумматор и переходит к выходной точке S₂₃, а также обратно через множитель *3, превращаясь в 3. Теперь второй имеет 2,4,8,... и 3,... в качестве входов; 2 проходит и превращается в 6. Далее имеет 4,8,16,... и 3,6,...; 3 проходит. Далее 4; и т. д. и т. д. и т. д. и т. п.

Таким образом, все элементы S₂ являются частью S₂₃, но также и все элементы S₂, которые прошли через множитель *3 один раз, дважды и т. Д., - все полномочия 2 и 3 , умноженные вместе в порядке возрастания:

S<sub>23</sub> = S<sub>2</sub> &cup; 3*S<sub>2</sub> &cup; 3*3*S<sub>2</sub>                   ;; = S<sub>2</sub> &cup; 3*( S<sub>2</sub> &cup; 3*S<sub>2</sub> 
                &cup; 3*3*3*S<sub>2</sub>                 ;;               &cup; 3*3*S<sub>2</sub> 
                &cup; 3*3*3*3*S<sub>2</sub>               ;;               &cup; 3*3*3*S<sub>2</sub> 
                &cup; ..........               ;;               &cup; ........ )   !!

Почему увеличивается порядок? Как? Да ведь это ответственность ! Здравствуйте, еще одно обнаруженное требование. Что бы ни поступало в него с обеих сторон, оно должно производить меньший элемент перед большим.

А что делать, если оба равны? Нужно ли нам заниматься этим вопросом в этой схеме здесь? Может ли это когда-нибудь случиться здесь?

Не может. И поэтому мы можем реализовать здесь как merge, а не как union (но помните первое обнаруженное требование! - оно все еще действует? Необходимо?) С помощью добавление новых случаев ). Merge должно быть более эффективным, чем union, поскольку оно не касается случая равных.

А для кратных 5 тоже? Мы продолжаем, как

S<sub>235</sub> = S<sub>23</sub> &cup; 5*S<sub>235</sub>

 {1} ----∪-->--->--S₂--.---S₂----∪-->--->--S₂₃--.---S₂₃----∪-->--->--S₂₃₅--.--->S₂₃₅
        /               \       /                \         /                 \ 
        \______*2_______/       \______*3________/         \_______*5________/ 
          ---<----<---            ---<----<---                ---<----<---     
  • Описывает ли это код из книги? _______
  • Описывает ли это код, который примерно в два раза быстрее кода из книги?_______
  • Почему это примерно в два раза быстрее, чем код из книги?_______
  • Этот ответ ваш вопрос?_______
  • Помогает ли это вам ответить на ваш вопрос?_______

(заполните пробелы).

См. Также:


И блок-схема обработки сигналов для кода книги:

                                  1 --->---\
                                             cons-stream ->-- S ---.---> S
    /----->---->--- *2 --->---\            /                       |
   /                            union ->--/                        /
  .-->-- *3 -->--\            /                                   /
  |                union ->--/                                   /
  .-->-- *5 -->--/                                              /
  \                                                            /
   \__________<__________<__________<_________<_______________/

, где "объединение" удаления дубликатов называется merge вкнига.

2 голосов
/ 13 апреля 2019

Это моя лучшая попытка визуализировать это. Но я борюсь, это похоже на змею с тремя головами, которая ест свой хвост.

If we say the values of the stream S are s0, s1, s2, ..., then 
initially we only know the first value, s0.

               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    ?    ?    ?    ?    ?    ?    ?    ?    ?    ?  

But we do know the three scale-streams will be producing multiples of
these values, on demand:

               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    ?    ?    ?    ?    ?    ?    ?    ?    ?    ?  

    scale-2:   2*1  2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?
    scale-3:   3*1  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?
    scale-5:   5*1  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    ________________________________________________________________


Merge will initially select the lowest of the numbers at the heads of
these three streams, forcing their calculation in the process:

               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    ?    ?    ?    ?    ?    ?    ?    ?    ?    ?  

    scale-2:  [2]  2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?
    scale-3:   3   3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?
    scale-5:   5   5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    ________________________________________________________________


 So s1 will now have the value 2:

               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1   [2]   ?    ?    ?    ?    ?    ?    ?    ?    ?  

    scale-2:        2*2  2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?
    scale-3:   3    3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?
    scale-5:   5    5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    ________________________________________________________________


Merge will now select 3 as the minimum of 4, 3, and 5:

               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    2    ?    ?    ?    ?    ?    ?    ?    ?    ?  

    scale-2:        4    2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?
    scale-3:  [3]   3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?
    scale-5:   5    5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    ________________________________________________________________


and will put it into the next slot in the result stream S, s2:

               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    2   [3]   ?    ?    ?    ?    ?    ?    ?    ?  

    scale-2:        4    2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?
    scale-3:        3*2  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?
    scale-5:   5    5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    ________________________________________________________________


Scale-2's head is selected again:

               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    2    3   [4]   ?    ?    ?    ?    ?    ?    ?  

    scale-2:             2*3  2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?
    scale-3:        6    3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?
    scale-5:   5    5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    ________________________________________________________________


And then 5 is selected from scale-5 and placed in the result:

               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    2    3    4   [5]   ?    ?    ?    ?    ?    ?  

    scale-2:             6    2*?  2*?  2*?  2*?  2*?  2*?  2*?  2*?
    scale-3:        6    3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?
    scale-5:        5*2  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    ________________________________________________________________


Two streams have 6 at their head, both are consumed but only one 6 
is placed in the result:

               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    2    3    4    5   [6]   ?    ?    ?    ?    ?  

    scale-2:                  2*4  2*?  2*?  2*?  2*?  2*?  2*?  2*?
    scale-3:             3*3  3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?
    scale-5:        10   5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    ________________________________________________________________


And a few more iterations:

               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    2    3    4    5    6   [8]   ?    ?    ?    ?  

    scale-2:                       2*5  2*?  2*?  2*?  2*?  2*?  2*?
    scale-3:             9    3*?  3*?  3*?  3*?  3*?  3*?  3*?  3*?
    scale-5:        10   5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    ________________________________________________________________


               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    2    3    4    5    6    8   [9]   ?    ?    ?  

    scale-2:                       10   2*?  2*?  2*?  2*?  2*?  2*?
    scale-3:                  3*4  3*?  3*?  3*?  3*?  3*?  3*?  3*?
    scale-5:        10   5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    _________________________________________________________________


               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    2    3    4    5    6    8    9   [10]  ?    ?  

    scale-2:                            2*6  2*?  2*?  2*?  2*?  2*?
    scale-3:                  12   3*?  3*?  3*?  3*?  3*?  3*?  3*?
    scale-5:             5*3  5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    ________________________________________________________________


               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    2    3    4    5    6    8    9    10  [12]  ?  

    scale-2:                                 2*8  2*?  2*?  2*?  2*?
    scale-3:                       3*5  3*?  3*?  3*?  3*?  3*?  3*?
    scale-5:             15   5*?  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    _________________________________________________________________


               s0   s1   s2   s3   s4   s5   s6   s7   s8   s9   s10
           S = 1    2    3    4    5    6    8    9    10   12  [15]

    scale-2:                                 16   2*?  2*?  2*?  2*?
    scale-3:                            3*6  3*?  3*?  3*?  3*?  3*?
    scale-5:                  5*4  5*?  5*?  5*?  5*?  5*?  5*?  5*?
    ________________________________________________________________

Так что, возможно, это больше похоже на змею с одной головой, которая поочередно кусает свои три хвоста.

...