Почему список значений `(read)` в Scheme имеет обратный порядок? - PullRequest
0 голосов
/ 28 декабря 2018

Я пытаюсь прочитать из файла в Scheme, и мне интересно, почему нужно перевернуть список после получения значений с помощью (read) или (read-line).Пример:

]=> (list 1 (read) 2 (read) 3)
Hello
world

;Value 39: (1 world 2 hello 3)

Почему «world» предшествует «hello» в результирующем списке?Приветствия.

Ответы [ 3 ]

0 голосов
/ 29 декабря 2018

Я думаю, что понял.Поскольку каждый список в Схеме фактически является рекурсией (cons ...), вышеупомянутый список фактически является:

(cons
  1
  (cons
    (read)        ; (2)
    (cons
      2
      (cons
        (read)    ; (1)
        (cons
          3
          '()
        )
      )
    )
  )
)

Таким образом, становится понятно, почему (read) помечен (1), оценивается до (read) помечен(2).

0 голосов
/ 29 декабря 2018

Порядок оценки аргументов по стандарту не определен.Вот часть из отчета R6RS :

Примечание: ‌ В отличие от других диалектов Лиспа, порядок оценки не указан , иВыражение оператора и выражения операнда всегда оцениваются с использованием одних и тех же правил оценки.

Хотя порядок вычисления в противном случае не определен, влияние любой параллельной оценки выражений оператора и операнда ограничено, чтобы быть совместимым с некоторыми последовательнымипорядок оценки.Порядок оценки может быть выбран по-разному для каждого вызова процедуры.

Вот пример:

(define (debug x)
  (display x)
  x)

(define (add x y)
  (debug (+ (debug x) (debug y))))

(add (add 3 4)
     (add 5 6))
; ==> 18

Вот возможные результаты от вызовов display:

347561171118 ; strictly left to right
651143771118 ; strictly right to left
561134771118 ; ltr in add, rtl in call to add (consistent)
437651111718 ; rtl in add, ltr in call to add (consistent)

В качестве примеров я знаю, что MIT Scheme работает строго справа налево, а DrRacket - слева направо.Икарус сделал третий.

Причина, по которой они недооцениваются, заключается в том, чтобы допустить неизвестную оптимизацию во время написания спецификации.Это не часто порядок важен, особенно если вы пишете это идиоматично.Если вам нужен правильный порядок, вы можете написать его так:

(let ((r1 (read)))
  (let ((r2 (read)))
    (list 1 r1 2 r2 3)))

Поскольку привязки всегда оцениваются перед тем, как вы будете в безопасности.Это имеет снимок, поэтому вы можете написать его как let*:

(let* ((r1 (read))
       (r2 (read)))
  (list 1 r1 2 r2 3))
0 голосов
/ 28 декабря 2018

Порядок, в котором оцениваются аргументы функции, не определяется языком Схемы.То есть при оценке (f (g) (h)) не определено, происходит ли вызов g до или после вызова h (только то, что оба происходят до вызова f).

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

Для того, чтобы вызовы происходили в нужном вам порядке, вы должны использовать let или define для сохранения результатов read в переменных до вызова list.

...