Функции
Определение функции происходит с помощью операторов создания объектов, имя функции должно соответствовать правилам именования, после которого указываются круглые скобки. В настоящий момент поддерживается создание функций только в качестве статических объектов с однократной инициализацией с помощью оператора ‘::=’;
Телом функции должен быть блок кода, который располагается в пространстве имен определения этой функции.
Функции поддерживают аргументы по умолчанию, а сами аргументы указываются как в Python, т.е. вначале идут обязательные, далее идут аргументы со значениями по умолчанию, где его имя отделяется от дефолтного значения знаком равно “=”.
Если функция допускает обработку произвольного количества аргументов, то последним в списке параметров должно быть указано многоточие “…”.
У аргументов функции может быть указан допустимый тип данных. Тип возвращаемого значения указывается после закрывающей скобки.
У аргументов и у типа возвращаемого значения можно указать сразу несколько допустимых типов данных.
Для этого их необходимо перечислить через запятую и заключить в угловые скобки, т.е.*
func(arg:<:Int8, :Int16, :Int32>): <:Int8, :Int16, :Int32> ::= {$arg*$arg};
*) Данная функциональность запланирована, но пока не реализована
Для создания функций используются те же правила синтаксиса и операторы, что и для создания переменных, только после имени функции обязательно должны быть указаны круглые скобки.
Синтаксис NewLang поддерживает два типа функций: обычные и чистые функции.
Обычные функции
Обычная функция — такие функции являются именно обычными функциями в понимании С/С++. Внутри них можно писать совершенно любой код, включая проверки условий, циклы, вызовы других функций и т.д. ?????????????????????????????
hello(str) ::= {
$printf ::= :Pointer('printf(format:FmtChar, ...):Int32');
$printf('call: %s', $str);
$str;
};
hello('Привет, мир!');
Чистые функции
Чистая функция — это тоже обычная функция, только в том смысле, какой в него вкладывает функциональное программирование.
У чистой функции отсутствует доступ к контексту и глобальным переменным, поэтому она может обрабатывать только те данные, которые были ей переданы в качестве аргументов.
Создание чистой функции происходит с помощью операторов :- или ::-, а сам оператор заимствован из языка Пролог. ???????????????????????????????? Чистые фунции, так же как и обычные, тоже могут быть только статическими объектами, поэтому их нельзя определять с именами лоакльных объектов.
Sum2(arg1, arg2) ::- {$arg1+$arg2;}; # Тоже самое, но если функция с таким именем уже существует, то будет ошибка
???????????????????????????????????????????????????
Sum1(arg1, arg2) :- {$arg1+$arg2;}; # Создать или переопределить простую функцию, которая возвращает сумму аргументов
Лямбда функции
Лямбда функции, это анонимная функция без указания имени, т.е. вместо имени функции стоит подчерк, и её нельзя вызвать по имени. Но зато лямбда функцию можно передавать как аругмент в другие функции, например при создании итератора.
_()::={ ... };
Корутины
Любую функцию можно определить как корутину (сопрограмма, Coroutine) - функция, выполнение которой можно прерываться явно методами языка программирования. В отличие от прерывания выполнения потока (thread), который реализован средствами ОС и его переключение происходит неявно и в произвольный момент времени.
func() ::= (){ ... };
Переопределение функций
Перегрузка функций по типам аргументов NewLang отсуствует, поэтому нельзя создать несколько функций с однинаковым именем, но разными типами аругментов. Но можно переопределить функцию с помощью оператора “[]=”, а в теле новой функции обратиться к первоначальной функции по системному имени “$$”.
«Требование от субтипов: пусть φ(x) — свойство, доказуемое относительно объектов x типа T. Тогда φ(y) должно быть истинно для объектов y типа S, где S — субтип T»12.
Это называется принципом подстановки Лисков. Я не буду вдаваться в подробности, но основной смысл в том, что любое предусловие (для типов, данных или состояния) параметров не может быть строже, чем для супертипа, а любое постусловие не может быть слабее, чем у супертипа13. Эта формулировка связана с методологией контрактного программирования, зародившегося примерно в то же время.
Новая функция должна иметь аргументы, совместимые с типом аргумента первоначальной функцией.
func(arg:Int8):Int8 ::= ... ;
func(arg:Int16):Int16 = ... ; # ОК Int8 -> Int16
func(arg:String):Int16 = ... ; # Ошибка String -> Int16
func(arg:Int16, arg2:Int16):Int16 = ... ;
func(arg:Integer, ...):Integer = ... ; # ОК обобщенные тип