Что такое функция reword в Rebol и как ее использовать?

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

1 ответ

Решение

Здесь будут драконы!

reword Функция - это небольшой эксперимент по добавлению интерполяции строк в стиле оболочки в Rebol таким образом, чтобы это работало так, как мы это делаем. В отличие от многих функций серии Rebol, он действительно оптимизирован для работы только с строковыми типами, и дизайн отражает это. Текущая версия является прототипом проекта, который должен быть переделан как "родной", но он работает так, как задумано, поэтому имеет смысл поговорить о том, как он работает и как его использовать.

Что значит reword делать?

В основном это:

>> reword "$a is $b." [a "This" b "that"]
== "This is that."

Он принимает строку шаблона, ищет escape-последовательности и заменяет их соответствующими значениями подстановки. Значения также передаются в функцию в виде объекта, карты или блока ключей и значений. Ключи могут быть практически любыми, даже цифрами:

>> reword "$1 is $2." [1 "This" 2 "that"]
== "This is that."

Ключи преобразуются в строки, если они еще не являются строками. Ключи считаются одинаковыми, если они будут преобразованы в одну строку, что происходит, когда вы делаете что-то вроде этого:

>> reword "A $a is $a." [a "fox" "a" "brown"]
== "A brown is brown."

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

Вы также можете использовать другие escape-флаги, даже многосимвольные:

>> reword/escape "A %%a is %%b." [a "fox" b "brown"] "%%"
== "A fox is brown."

Или даже вообще не иметь escape-флага, и он заменит ключ везде:

>> reword/escape "I am answering you." [I "Brian" am "is" you "Adrian"] none
== "Brian is answerBrianng Adrian."

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

>> reword/escape "I am answering you." ["I am" "Brian is" you "Adrian"] none
== "Brian is answering Adrian."

Все еще делаю reword шаблоны без escape-символов, как правило, хитрые и немного медленнее, поэтому это делается не так часто.

Хотя есть еще лучший трюк...

Замена функции

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

>> reword "$x then $x and $x, also $x" object [y: 1 x: does [++ y]]
== "1 then 2 and 3, also 4"

Или, может быть, даже позиция, поскольку она может принимать позицию строки в качестве параметра:

>> reword "$x then $x and $x, also $x" object [x: func [s] [index? s]]
== "1 then 9 and 16, also 25"

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

>> reword "$x or $y" object [x: y: func [s] [ajoin ["(it's " copy/part s 2 ")"]]]
== "(it's $x) or (it's $y)"

Смотрите, переменные шаблона, экранирование и все. И функция может иметь побочные эффекты, такие как счетчик строк:

>> reword/escape "Hello^/There^/nl" use [x] [x: 0 map reduce ["^/" does [++ x "^/"] "nl" does [x]]] ""
== "Hello^/There^/2"

Это даже идет с /into вариант, так что вы можете использовать его для поэтапного построения строк.

Но большая проблема для кого-то, пришедшего из языка со встроенной интерполяцией, это...

Почему блок значений, почему бы просто не использовать переменные как обычный язык?

Потому что Ребол просто так не работает. У Rebol нет лексической привязки, он делает что-то еще, поэтому в строке просто нет способа узнать, где можно получить значения переменных, не говоря об этом. В одном из тех языков оболочки, который имеет интерполяцию, это было бы эквивалентно необходимости передавать ссылку на среду в целом в функцию интерполяции. Но, эй, мы можем сделать это в Rebol:

>> use [x] [x: func [s] [index? s] reword "$x then $x and $x, also $x" bind? 'x]
== "1 then 9 and 16, also 25"

Тот bind? метод будет работать в use, связывание петель и функций. Если вы находитесь в объекте, вы также можете использовать self:

>> o: object [x: func [s] [index? s] y: func [s] [reword s self]]
== make object! [
    x: make function! [[s][index? s]]
    y: make function! [[s][reword s self]]
]
>> o/y "$x then $x and $x, also $x"
== "1 then 9 and 16, also 25"

Но будьте осторожны, иначе вы можете сделать что-то вроде этого:

>> o/y "$x then $x and $x, also $x, finally $y"
** Internal error: stack overflow

Драконы! Это одна из веских причин держать ваши переменные и ключи замены отдельно...

Другие вопросы по тегам