Функции

Определение функции происходит с помощью операторов создания объектов, имя функции должно соответствовать правилам именования, после которого указываются круглые скобки. В настоящий момент поддерживается создание функций только в качестве статических объектов с однократной инициализацией с помощью оператора ‘::=;

Телом функции должен быть блок кода, который располагается в пространстве имен определения этой функции.

Функции поддерживают аргументы по умолчанию, а сами аргументы указываются как в 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 =  ... ; # ОК обобщенные тип