На жаль, всі самонавчальні алгоритми досить складні і об'ємні. Логіка самонавчання алгоритму, як і раніше, залишається завданням програміста. Але, не дивлячись на це, я наведу приклад класичного завдання на самонавчання.
Завдання полягає в тому, щоб дати відповідь, чи є вказане число простим. На перший погляд нічого особливого. Але проблема полягає в тому, що для того, щоб дати правильну відповідь, потрібно знайти задане число в ряді простих чисел. Іншого способу просто не існує. А цей ряд нескінченний. Зрозуміло, ми можемо задати в пам'яті тільки обмежений відрізок ряду, і виходить, що як не крути, а задане число може перевищувати обмеження. Звичайно, ви скажіть, що ряд легко продовжити. Так, ви абсолютно праві. Але з точки зору оптимізації роботи програми, за часом, незручно кожен раз обчислювати одне і теж, а краще зберігати масив простих чисел, кожен раз при доповненні його. Власне в цьому і полягає міра навчання цього класичного завдання. З точки зору класичного програмування нам потрібно організувати сховище для вмісту масиву відомих простих чисел, наприклад в окремому файлі, або в базі даних. Але спираючись на можливість мови «Автор» вносити зміни програм у власний код можна зробити таке сховище прямо всередині коду програми.
//prosto.txt//найпростіша
самонавчальна програма пошуку простих чисель.var
isProsto (n) {
m = {2,3,5,7}
; if(n<0)return #
; ok=0
; if(n==0 || n==1)ok=1
; for(i=0;i<m.size();++i)
{ if(n==m[i]){ok=1;break;
} if(n<m[i])break
;
} if(i==m.size())
{ u=m[i-1]
; oknew=0
; do
{ ++u
; uok=1
; for(i=0;i<m.size();++i)if(!(u%m[i])){uok=0;break;
} if(uok)
{ oknew=1
; m.push(u)
; if(u==n)ok=1
;
} }while(n>u)
; if(oknew)
{ f=getFunction(getThisFunctionName())
; pos=f.Root()
; pos=f.Next(pos)
; f.setComand(pos,""m=""+m.export())
;
}
} return ok
;
}void main()
{ ok=isProsto(n=200)
; trace («Число» + n + (ok? «» «»:«» не «») + «»
просте «».);}
Все завдання полягає у виклику функції «isProsto (n)» з заданим числом для аналізу. Власне в змінній «m» і міститься наше сховище. Для заміни команди у схемі алгоритму використовується функція «f.setComand (pos», m = {2,3} «)», яку потрібно викликати від об'єкта функції. Першим параметром потрібно вказати ідентифікатор вузла з командою в граф-схемі алгоритму, яку (команду) слід замінити, а другим об'єкт команди (дерева операторів). Другим параметром може бути і рядок тексту, який неявно перетворюється (розпарситься). Щоб отримати ідентифікатор вузла, скористайтеся тим фактом, що масив/сховище знаходиться на першому вузлі від початку алгоритму функції. Функція «f.Root ()» поверне ідентифікатор першого і останнього вузла схеми, так би мовити вузол початку алгоритму. Ви можете перейти до вузла, гарантовано, одного, першого вузла. А ось піднімаючись вгору з першого і останнього вузла («f.Up (pos)») можливо отримати безліч (масив ідентифікаторів) вузлів, якими закінчується алгоритм. Справа в тому, що в кінці алгоритму може розташовуватися умовний оператор з гілкою, що веде до вузла началоконца.
Подивимося, на що перетворилася наша функція після запуску програми.
// prosto.code
void isProsto(var n){
m={
2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,
67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,
139,149,151,157,163,167,173,179,181,191,193,197,199
};
if(n<0)return # ;
ok=0;
if(n==0||n==1)ok=1;
i=0;
for(;i<m.size();++i){
if(n==m[i]){
ok=1;
break;
}
if(n<m[i])break;
}
if(i==m.size()){
u=m[i-1];
oknew=0;
do{
++u;
uok=1;
i=0;
for(;i<m.size();++i)if(!u%m[i]){
uok=0;
break;
};
if(uok){
oknew=1;
m.push(u);
if(u==n)ok=1;
}
}while(n>u);
if(oknew){
f=getFunction(getThisFunctionName());
pos=f.Root();
pos=f.Next(pos);
f.setComand(pos,""m=""+m.export());
}
}
return ok;
}
У мові «Автор» також є можливість використання міток, за якими можна знайти ідентифікатори відповідних їм вузлів у схемі алгоритму. Кожна мітка містить номер, який повинен бути унікальний в приладах функції.
Розгляньмо наступне завдання. У програмах буває так, що потрібно виконати якісь складні обчислення з константами, які займають час, і які достатньо зробити тільки один раз, скажімо при написанні програми, щоб не витрачати час кожен раз при новому запуску на одні і ті ж обчислення. Подивимося, як можна використовувати можливість мови, трансформувати скрипт, для вирішення цього завдання.
// one.txt
void main(){
trace(""Helloy World!!!"");
<label:10 >
if (1) {
x = 1 + 1 ;//складні обчислення
f = getFunction (getThisFunc^ Name ());
pos = f.getLabel (10) ;//шукаємо мітку
pos = f.insertDown (pos);
f.setCommand(pos,""x=""+x);
pos=f.Down(pos);
command=f.getCommand(pos);
command.setSub({0},PROGRAM(""0""));
f.setCommand(pos,command);
}
trace(x);
getstring();
}
В даному випадку, програма, звичайно ж, видасть на екран «2». Але подивимося, як виглядає файл дублікат коду, з якого інтерпретатор будить брати код програми, вже після першого запуску.
// one.code
void main(){
trace(""Helloy World!!!"");
<label:10>
x=2;
if(0){
x=1+1;
f=getFunction(getThisFunctionName());
pos=f.getLabel(10);
pos=f.insertDown(pos);
f.setCommand(pos,""x=""+x);
pos=f.Down(pos);
command=f.getCommand(pos);
command.setSub({0},PROGRAM(""0""));
f.setCommand(pos,command);
}
trace(x);
getstring();
}
// one.code :-|
Звичайно ж, все можна організувати і по іншому, залежно від складності завдання. Я просто хотів продемонструвати перспективи, які відкриваються з можливістю програм змінювати власний код.
Також у мові є особлива системна функція «Spirit ();», яка саме видаляється при першому своєму виконанні. Вона приймає ім'я функції і аргументи до неї. Так що виходить, що зазначена функція викличеться тільки одного разу і від цього не залишиться ніяких слідів.
// Spirit.txt
firstprocess(namef,n){
x=100*(1+1);
f=getFunction(namef);
pos=f.getLabel(n);
f.setCommand(pos,PROGRAM(""k=""+x));
return 1;
}
void main(){
Spirit(""firstprocess"",getThisFunctionName(),10);
<label:10>
trace(""k=""+k);
getstring();
}
Ця програма виведе на екран «k = 200» і ось на що перетвориться.
// Spirit.code
int firstprocess(var namef,var n){
x=100*(1+1);
f=getFunction(namef);
pos=f.getLabel(n);
f.setCommand(pos,PROGRAM(""k=""+x));
return 1;
}
void main(){
k=200;
trace(""k=""+k);
getstring();
}
// Spirit.code :-|
Цікаво (?) | Слід продовжувати