1.10.2. ЗАДАЧА О ЦЕПОЧКАХ Рассмотрим следующую задачу [Вир 77]. Требуется найти объектное выражение Oe, обладающее следующими свойствами.
(1) | Oe не содержит скобок, а всякий входящий в него символ является одним из символов 1, 2 или 3. | |
(2) | Oe имеет заданную длину len. | |
(3) | Не существует таких
объектных выражений Oea, Oeb и Oec,
что Oec - не пусто и при этом Oe = Oea Oec Oec Oeb т.е. Oe не содержит двух смежных непустых совпадающих подвыражения. |
|
Для построения требуемого выражения можно поступить следующим образом: начать с пустого выражения, а затем постепенно добавлять к нему числа, следя за тем, чтобы не получалось запрещенной комбинации. При этом, чтобы гарантировать, что цепочка не имеет вида Oea Oec Oec Oeb, где Oec - непустое, достаточно после добавления каждого числа проверять, что не образовалось выражение вида
Oea Oec Oec
Для распознавания выражений такого вида определим предикат Unacceptable?.$func? Unacceptable? e.String = ;
Unacceptable? e.String =
<Div <Length e.String> 2> :: s.Max,
{
s.Max : 0
= $fail;
= 1
$iter \{ <"<" (sK) (s.Max)> = <"+" sK 1>; }
:: sK,
<Right 0 sK <Middle 0 sK e.String>> :: eU,
<Right 0 sK e.String> :: eV,
eU : eV;
};
Теперь определим функцию Extend?, которая пытается добавить к выражению очередной символ, пока цепочка не достигнет заданной длины. Если цепочку продолжить невозможно, происходит возврат назад, и делается попытка изменить предыдущие символы.$func? Extend? s.Len e.String = e.String;
Extend? s.Len e.String =
{
<Length e.String> : s.Len
= e.String;
= 1 $iter \{ <"<" (s.Digit) (3)> = <"+" s.Digit 1>; }
:: s.Digit,
e.String s.Digit :: e.String,
# <Unacceptable? e.String>,
<Extend? s.Len e.String>;
};
Теперь осталось определить начальную функцию Find-String?, которая получает в качестве параметра желаемую длину цепочки, и выдает искомую цепочку (если она существует), либо терпит неудачу (если она не существует).$func? Find-String? s.Len = e.String;
Find-String? s.Len =
<Extend? s.Len >;