Сегодня мы поздравляем: AMF, sinyakin,
Раздел статей

Статьи портала->->Как программировать на функциональных языках. [ Поиск ]

Как программировать на функциональных языках.
Название Как программировать на функциональных языках.
Описание Введение во взрослую жизнь от дяди Creator'a
Уровень: Новичок наркомании
Редакторы: Notepad++
Форматы: .txt
Автор: Creator
Добавил Unwelcom

В данном руководстве освещаются общие принципы программирования на любых функциональных языках.

Первое, что надо знать – это то, что бывают 2 вида языков программирования: декларативные и функциональные.

В декларативном языке указываются только настройки и свойства каких-либо объектов. Пример такого языка – это хорошо всем известный INI-код игр Generals, СnC-3 и Red alert-3. К декларативным языкам также относятся XML, HTML, XAML, XQuery и другие. Подробно их рассматривать не будем, так как модостроители уже давно с их принципами знакомы.


Вторая ветвь языков – это функциональные. Они не имеют ничего общего с декларативными. Здесь основные принципы совсем другие. Основа функциональных языков – это алгоритм. То есть, последовательность действий. Действия выполняются именно в той последовательности, которая указана в коде и ее изменение может повлиять на результат.

Для того, чтобы было интуитивно понятно, что такое алгоритм, разберем простейший пример из жизни – приготовление яичницы:
1. Включить плиту.
2. Поставить сковородку на плиту.
3. Налить масло в сковородку.
4. Разбить яйцо.
5. Вылить яйцо на сковородку.
6. Посолить.
7. Ждать до полной готовности.
Вот это и есть пример алгоритма. Можно менять местами действия 1 и 2. Можно действие 1 поставить на любое место кроме последнего. Можно действие 2 поставить на любое место кроме последнего. Но, действия 4 и 5 уже поменять нельзя, так как 5-е зависит от результатов выполнения 4-го. А результат 7-го зависит от результатов выполнения всех 6 предыдущих действий. Любое действие в функциональном языке называется оператором.

Теперь перейдем к другому примеру. Ниже написан код выстрела из ракетницы на языке QC для Quake-1.


void() W_FireRocket = // название функции выстрела
{
local entity missile; // определение локальной переменной

self.currentammo = self.ammo_rockets = self.ammo_rockets - 1; // отнимаем одну ракету из боезапаса игрока

sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM); // воспроизвести звук выстрела

self.punchangle_x = -2; // отдача

missile = spawn (); // создать объект
missile.owner = self; // присвоить ссылку на того, кто стреляет
missile.movetype = MOVETYPE_FLYMISSILE; // задать тип движения (двигается по прямой)
missile.solid = SOLID_BBOX; // сделать ракету твердой, чтобы могла сталкиваться с чем-либо.

makevectors (self.v_angle); // определить, куда смотрит игрок
missile.velocity = aim(self, 1000); // задать направление ракеты
missile.velocity = missile.velocity * 1000; // задать скорость ракеты
missile.angles = vectoangles(missile.velocity); // развернуть ракету в направлении полета

missile.touch = T_MissileTouch; // задать функцию взрыва. При столкновении будет вызвана функция T_MissileTouch, которая нарисует взрыв и принесет повреждения.

missile.nextthink = time + 5; // задать время жизни.
missile.think = SUB_Remove; // при истечении времени жизни будет вызвана функция SUB_Remove, которая тихо удалит ракету без взрыва.

setmodel (missile, "progs/missile.mdl"); // задать 3D-модель ракеты
setsize (missile, '0 0 0', '0 0 0'); // задать размер ракеты (в данном случае, это точка)
setorigin (missile, self.origin + v_forward*8 + '0 0 16'); // ну, и самое главное, задать местоположение ракеты. То есть, откуда она будет вылетать.



Обратите внимание, что если мы переставим местами строчки:
missile = spawn();
missile.owner = self;
то будет вылет. Для того, чтобы работать с объектом, его сначала нужно создать. Если мы переставим местами строчки:
missile.velocity = aim(self, 1000);
missile.velocity = missile.velocity * 1000;
то ракета не полетит. Чтобы задать скорость, нужно сначала задать направление в виде вектора единичной длины. Если мы перенесем вверх строчку:
missile.angles = vectoangles(missile.velocity);
то ракета не развернется как надо и будет лететь боком. Для того, чтобы развернуть ракету, сначала надо задать направление движения. Хотя, строчки:
missile.velocity = missile.velocity * 1000;
missile.angles = vectoangles(missile.velocity);
менять местами можно – они друг на друга не влияют.


То есть, если в Generals мы могли писать параметры как хотели, то тут уже надо думать о последовательностях и зависимостях.


Переменные. В каждом функциональном языке есть переменные. В декларативных языках их нет. Что же это такое? В тех же Generals вы часто сталкивались с заданием значений. Например, health = 100 или PrimaryDamage = 25. Фактически, это и есть переменные. Отличие только одно. В декларативном языке они задаются один раз, а в функциональном они могут менять свое значение. Например, мы один раз присвоили health = 100, а потом, во время игры мы можем сделать health = 50, либо отнять значение health = health – 10 (отнять 10 от текущего значения). Можно и прибавить health = health + 10, делить умножать, вычислять что-то и как угодно менять любые параметры в процессе игры.


Типы. Каждая переменная имеет свой тип. Чтобы лучше понять, что это такое, представьте себе ящик. Есть, например, ящик с надписью «гвозди» - робот кладет в него только гвозди. Есть ящик с надписью «гайки» - робот кладет в него только гайки. Вот надпись – это и есть тип. А ящик – это переменная. Переменная задается, как правило, в начале функции. Например (C++):
int a,b;
float x,y;
a,b,x и y – это переменные, а int и float – это их типы. В переменные a и b можно класть только целые числа (int - целое), а в переменные x и y можно класть только дробные числа (float - дробное). Как правило, во всех языках типы повторяются. Ниже я приведу то, что можно встретить почти везде.

int, integer, short, long, word, dword, byte – целые числа
float, real, single, double, decimal – дробные числа
string, char – строки
bool, boolean – двоичный тип, который может хранить только одно из двух возможных значений: true или false.


Следует отметить, что разные целые типы могут хранить числа разных размеров. Это можно сравнить с ящиками разных размеров. Есть, например, маленький ящичек для маленьких гвоздиков, в который огромный 30-см гвоздь не влезет – для него нужен большой ящик. Тут также. В byte может влезть число максимум до 255, а если нужно хранить большие числа, что возьмите word – в него помещается число вплоть до 65535. Ну, и так далее. Так во всех языках. Когда будете изучать, обратите внимание, какой тип что может хранить. Также, любой язык имеет свои уникальные типы. Например, в QC есть тип entity, которого нигде больше нет. В Quake он обозначает любой объект игрового мира.


Часто встречающиеся операторы и кодовые слова:


Операторные скобки – { } – это фигурные скобки, представляющие собой цельный и неделимый блок операторов. Зачем надо – поясню ниже. В некоторых языках вместо скобок используются слова begin / end, либо просто end без begin


If / then / else – оператор условия. Работает так: if (условие) then (что делать, если условие выполняется) else (что делать, если условие не выполняется). Вы это уже встречали в редакторах карт для многих игр. В некоторых языках не пишется слово then. После then и после else можно поставить только один оператор. А что делать, если надо много? А тогда надо ставить те самые операторные скобки.

If (условие) then
{
Оператор 1;
Оператор 2;
Оператор 3;
}
Else
{
Оператор 4;
Оператор 5;
Оператор 6;
}


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

For, while, do, repeat – операторы цикла. Если какую-то последовательность действий нужно повторить несколько раз, то ее не нужно копировать – достаточно поместить ее внутрь цикла и задать число повторений. Синтаксис операторов цикла разный в разных языках и сильно отличается друг от друга. Поэтому, не буду здесь подробно все объяснять.

Return, Exit, Break – выход из чего-либо. Либо из функции, либо из цикла. В каждом языке может быть свое значение этих слов.

Null и Nil – отсутствие значения в переменной. Обычно, используется для ссылок.

goto - переход. Обычно, пишется что-то вроде goto label1 и где-то в коде присутствует label1: (да, с двоеточием). Это метка. Метка может иметь любое название. А goto - это переход к указанной метке. Когда программа встретит строку goto label1, она резко перепрыгнет к метке label1: и продолжит выполнять программу оттуда.

Далее нужно сказать, что весь функциональный язык построен по принципу коробочка в коробочке. То есть, операторы и переменные существуют не сами по себе, а упаковываются в блоки, а те блоки в другие блоки, а те в еще большие блоки и так далее. Значения некоторых часто встречающихся «коробочек» я поясню.

Функция – коробочка для операторов и переменных. В ней можно писать любой алгоритм. Переменные действуют только во время выполнения функции. Как только функция завершилась, все содержимое переменных стирается. Если у вас какой-то алгоритм встречается часто, не нужно его каждый раз копировать – напишите функцию и вызывайте ее каждый раз, когда понадобится. А еще, из функций можно вызывать другие функции. Это удобно.

Функция может возвращать значения и принимать их. Происходит это так:
x = myfunc(1,2,3);
Собственно, 1,2,3 – это то, что я передаю в функцию. Когда она отработает, что возвратит мне значение и запишет его в переменную x.

Есть ограничение. Нельзя переходить от одной функции к другой через goto. А также, в одной функции нельзя использовать переменные, объявленные в другой функции.

Структура или запись (struct, record) – коробочка для переменных. Сама структура является типом. То есть, можно сделать так, чтобы переменная хранила внутри себя несколько других переменных. Пример использования структур приведен выше. Вы уже видели строку missile.owner = self. Так вот, missile – это переменная типа entity. Entity – это структура. Следовательно, missile содержит в себе много других переменных. Owner – это одна из них. Обращение к внутренностям происходит через точку missile [точка] owner.

Массив (array) – коробочка для значений одного типа. Одна переменная может хранить в себе одно значение. Но, массив – это тип. И, можно сделать так, чтобы переменная хранила в себе много значений. Например (С++),

byte a[5] // массив с 5 значениями типа байт
a[0] = 4;
a[1] = 6;
a[2] = 7;
a[3] = 8;
a[4] = 2;
Далее задаем значения каждому элементу массива. Обратите внимание, что у нас 5 значений, а нумерация идет от 0 до 4. В одних языках нумерация элементов массива идет от 0, а в других – от 1. На это тоже надо обращать внимание.

Класс (class) – коробочка для хранения функций и переменных. Класс и структура очень похожи друг на друга. Отличие только в том, что класс может хранить в себе функции. И да, класс тоже является типом. То есть, можно сделать переменную, которая внутри себя хранит и функции, и другие переменные.

Статические (static) функции. Как правило, класс – это тип. И, пока не задашь переменную типа класс, не сможешь вызывать функции, которые в этом классе присутствуют. Но, из этого есть выход. Внутри класса можно сделать статическую функцию, которая позволит вызывать себя без использования переменной. Вот, в чем разница:

Обычный класс с обычными функциями (C++):
CMyClass a; // объявляем переменную типа CMyClass.
a.MyFunc(); // вызываем функцию MyFunc из класса.
А вот класс со статической функцией:
CMyClass::MyFunc(); // вызываем функцию сразу, без переменной.
В одних языках обращение к статической функции происходит через двойное двоеточие (::) в других – через точку.

Пространство имен (namespace) – коробочка для классов. В некоторых языках namespace может хранить в себе другие namespace-ы.

Структура программы на современном языке, как правило, такая. Есть namespace-ы, внутри которых содержатся классы. Внутри классов – функции и переменные. Внутри функций еще и локальные переменные. Структуры – это необязательные вещи. Они могут быть, а могут не быть. Кроме того, в некоторых языках нет namespace-ов и программа просто представляет из себя набор классов. У некоторых языков нет классов. Тогда программа представляет собой набор функций, структур и переменных.

Как правило, программа не пишется с нуля. Есть огромное количество библиотек, которые содержат в себе уже готовые функции, классы и namespace-ы. Любая программа подключает библиотеки, которые планируется использовать. Например, в С++ подключение происходит так:
#include // подключить библиотеку математических функций.
В С# подключение происходит так:
using namespace std // подключить библиотеку базовых функций
И тому подобное. Если нужная библиотека не подключена, то ее функции недоступны. Стандартные библиотеки располагают функциями, которые имеют интуитивно понятные названия. Например, print, write – вывод строки; open, fopen – открытие файла; CString – класс работы со строками и так далее. Очень часто по имени функции или класса можно определить назначение.

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

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

Как запустить программу?

Нужно знать, что есть компилируемые языки и интерпретируемые. Для компилируемых языков нужен компилятор, который переведет программу в машинный код, сформирует запускной файл (для Windows - это exe) и только потом ее можно будет запускать. Многие современные компиляторы запускают программу сразу после компиляции. При этом, получившийся exe-файл можно найти на диске в нужной директории.

Есть оболочечные и безоболочечные компиляторы. Оболочечные - это где есть свой интерфейс типа как в Word - открываешь программу, есть кнопки для редактирования, компиляции и так далее. Например, Microsoft Visual Studio - оболочечный компилятор, способный переваривать 5 языков: С, С++, С#, F# и Visual Basic. Безоболочечный компилятор - это тот, что запускается из командной строки и на выходе выдает запускной файл не запуская его. Например, компилятор GCC для Unix-ов безоболочечный. К компилируемым языкам относятся С, C++, Pascal, Delphi, C#, F# и другие.

Интерпретируемые языки - это те, для которых нужен интерпретатор. В отличие от компилятора, интерпретатор не создает запускной файл - он читает программу и сразу же ее исполняет. Из-за этого все интерпретируемые языки работают медленнее, чем компилируемые, но имеют другую особенность - легкий перенос с одной ОС на другую. Например, exe-файлы нельзя переносить с Windows на Linux, код написанный на С++ для Windows тоже не будет компилироваться для Linux, а программы, написанные на Perl можно переносить без изменений. К интерпретируемым - Perl, LUA, Python и другие.

Голосов Голосов: 6 - В среднем: 5

Добавить комментарий Оценить
Комментарии
Unwelcom
01 Июнь 2012
Очень круто
Операторы радуют
Креатор, если меня маляшь переклинить на программирование, то подскажешь нубу из чего состоит вселенная?

Статистика
На данный момент 51 статей в Базе Данных
Лидер просмотров: Создание новых юнитов
Лидер по оценкам: Создание новых юнитов

Всего пользователей в разделе статей: 29 (0 Зарегистрированных пользователей 29 Гостей и 0 Анонимных)
Известные пользователи: 0
 

Воспроизведение материалов с данного сайта без разрешения редакции запрещено.
Реклама на нашем сайте.
Red System © 2001-2016 - All Rights Reserved