отрывок кода - PullRequest
       15

отрывок кода

2 голосов
/ 29 ноября 2011

Я читал какой-то код lisp и наткнулся на этот раздел, не совсем понял, что конкретно он делает, хотя вся функция должна подсчитывать, сколько раз буквы из -z появляются во введенном тексте.

(do ((i #.(char-code #\a) (1+ i)))
    ((> i #.(char-code #\z)))

Может кто-нибудь объяснить шаг за шагом, что происходит? Я знаю, что он как-то считает буквы, но не совсем уверен, как.

Ответы [ 3 ]

9 голосов
/ 29 ноября 2011

Этот код на Лиспе немного необычен, поскольку использует оценку времени чтения. #.expr означает, что выражение будет оцениваться только один раз, во время чтения.

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

Источник выглядит так:

(do ((i #.(char-code #\a) (1+ i)))
    ((> i #.(char-code #\z)))
  ...)

Когда Лисп читает в s-выражении, мы получаем в результате этот новый код (при условии обычной кодировки символов):

(do ((i 97 (1+ i)))
    ((> i 122))
  ...)

Итак, это цикл, который считает переменную i с 97 до 122.

1 голос
/ 29 ноября 2011

Лисп-коды записываются как S-выражение .В типичном синтаксисе S-выражения первый элемент любого S-выражения рассматривается как оператор, а остальные - как операнд.Операнды могут быть атомом или другим S-выражением.Обратите внимание, что атом - это один объект данных.Помня об этом

char-code

(char-code #\a) - returns the ascii representation of a character here its 'a'. 

Синтаксис do выглядит примерно так:

(do ((var1 init1 step1)
     (var2 init2 step2)
     ...)
    (end-test result)
 statement1
  ...)

Так в вашем примере

(do ((i #.(char-code #\a) (1+ i)))
    ((> i #.(char-code #\z)))
    )

Первый операнд s-выражения do - это инициализация цикла, второй операнд s-выражения - end-test.Таким образом, это означает, что вы просто перебираете 'от' до 'z', увеличивая i на 1.

В C ++ (Не уверен, что ваш уровень языкового комфорта вы можете написать

for(i='a';i<='z';i++);
0 голосов
/ 24 декабря 2011

уловка с кодом, который вы показываете, в плохой форме. я знаю это, потому что я делаю все это время. код предполагает, что компилятор будет знать текущее исправление за каждого персонажа. #. (char-code # \ a) eq [(или, может быть, eql, если вы так склонны), 8-битное целое без знака или 8-битное без знака с возвращаемым значением положительного фиксированного числа].

# - макрос для чтения (я уверен, что вы это знаете :). Использование двух макросов для чтения не очень хорошая идея, но это быстро, когда компилятор знает тип данных.

У меня есть другой пример. Нужно искать ascii в двоичном потоке:

(defmacro code-char= (byte1 byte2)
  (flet ((maybe-char-code (x) (if characterp x) (char-code x) x)))
       `(the fixnum (= (the fixnum ,(maybe-char-code byte1)
                       (the fixnum ,(maybe-char-code byte2)))))
))

Объявление типа возврата в sbcl, вероятно, оскорбляет компилятор, но я оставляю это как проверку работоспособности (4 меня, а не вы).

(code-char = # \ $ # x36) => т

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

Если вы серьезно заинтересованы, есть какой-нибудь ассемблер для 286 (8/16 битный DOS ассемблер), который вы можете использовать в таблице переходов. Он быстро работает на ПК, мне нужно его посмотреть ...

...