DeclarativeCOS — Декларативное программирование на Caché
Цель проекта — обратить внимание сообщества к улучшению внутреннего ядра COS.
Идея проекта — поддержка лаконичного синтаксиса при работе с циклами и коллекциями.
Итак, что же лаконичного я придумал? Добро пожаловать в примеры!
Примеры
Ключевой концепт проекта — декларативный подход. Нужно указать ЧТО нужно использовать и КАК.
Лично мне всегда не хватало простого оператора/команды/заклинания в терминале COS для того, чтобы вывести коллекцию на экран в том виде, в котором тебе это хочется. А теперь есть две приятные штуки: zforeach и $zjoin!
>s words = ##class(%ListOfDataTypes).%New()
>d words.Insert("Hello”)
>d words.Insert("World!”)
>zforeach $zbind(words, "io:println”)
Hello
World!
Здесь стоит рассказать подробнее о функции $zbind. Начать следует с того, что COS можно расширять своими командами и функциями, о чем можно подробно написано в соответствующей документации и статье на портале сообщества разработчиков.
Эта функция создает экземпляр класса Binder. Его задача — связать коллекцию и функцию, которую нужно применить к каждому элементу коллекции. В данном случае, используется стандартная функция с именем «io: println» из DeclarativeCOS, которая для заданного значения value выполняет простую команду:
>w value,!
Команда zforeach работает с экземпляром класса Binder, последовательно проходя по коллекции и применяя функцию к каждому ее элементу.
$zjoin — создает строку из коллекции, объединяя ее элементы между которыми добавляется указанный разделитель.
>s numbers = ##class(%ListOfDataTypes).%New()
>d numbers.Insert("04”)
>d numbers.Insert("03”)
>d numbers.Inset("2017”)
>w $zjoin(numbers, " / ”)
04 / 03 / 2017
$zmap — создает новую коллекцию из элементов исходной коллекции к каждому элементу которой применена указанная функция.
>set numbers = ##class(%ListOfDataTypes).%New()
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>write "[" _ $zjoin(numbers, ", ") _ "]"
[82, 12, 27]
>set hexNumbers = $zmap(numbers, "examples:toHex")
>write "[" _ $zjoin(hexNumbers, ", ") _ "]”
[52, C, 1B]
$zfind — находит первый элемент коллекции, на котором указанная функция возвращает $$$YES. Иначе возвращает null-строку.
>set numbers = ##class(%ListOfDataTypes).%New()
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>set primeNumber = $zfind(numbers, "examples:isPrime")
>write "[" _ $zjoin(numbers, ", ") _ "]"
[69, 41, 68]
>write "Prime number: " _ $select(primeNumber="":"", 1:primeNumber)
Prime number: 41
$zfilter — создает новую коллекцию на основе исходной коллекции, но взяв только те элементы, на которых указанная функция возвращает $$$YES. Если таких элементов нет, то возвращает пустую коллекцию.
>set numbers = ##class(%ListOfDataTypes).%New()
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>set filteredNumbers = $zfilter(numbers, "examples:isOdd")
>write "[" _ $zjoin(numbers, ", ") _ "]"
[22, 71, 31]
>write "[" _ $zjoin(filteredNumbers, ", ") _ "]"
[71, 31]
$zexists — проверяет, что в коллекции есть хотя бы один элемент, на котором указанная функция возвращает $$$YES.
>set numbers = ##class(%ListOfDataTypes).%New()
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>do numbers.Insert($random(100))
>set hasEvenNumbers = $zexists(numbers, "examples:isEven")
>write "[" _ $zjoin(numbers, ", ") _ "]"
[51, 56, 53]
>write "Collection has" _ $case(hasEvenNumbers, 1:" ", 0:" no ") _ "even numbers"
Collection has even numbers
$zcount — подсчитать количество элементов в коллекции, на которых указанная функция возвращает $$$YES.
>set numbers = ##class(%ListOfDataTypes).%New()
>do numbers.Insert($random(1000))
>do numbers.Insert($random(1000))
>do numbers.Insert($random(1000))
>set palindromicNumbersCount = $zcount(numbers, "examples:isPalindromic")
>write "[" _ $zjoin(numbers, ", ") _ "]"
[715, 202, 898]
>write "Count of palindromic numbers: " _ palindromicNumbersCount
Count of palindromic numbers: 2
Установка
Для установки DeclarativeCOS достаточно скачать с официального GitHub репозитория проекта два файла:
- install.base.xml — просто классы. Без z-функций.
- install.advanced.xml — %ZLANG рутины, которые добавляют z-функции.
Как пользоваться
- Унаследовать класс от DeclarativeCOS.DeclarativeProvider.
- Реализовать метод класса.
- Пометить этот метод аннотацией @Declarative.
- Использовать z-функции DeclarativeCOS.
- Почувствовать счастье.
Подробная инструкция
Class MyPackage.IO extends DeclarativeProvider
{
}
Class MyPackage.IO extends DeclarativeProvider
{
ClassMethod println(value As %String)
{
w value,!
}
}
Class MyPackage.IO extends DeclarativeProvider
{
/// @Declarative("myIO:myPrintln")
ClassMethod println(value As %String)
{
w value,!
}
}
>s words = ##class(%Library.ListOfDataTypes).%New()
>d words.Insert("Welcome")
>d words.Insert("to")
>d words.Insert("DeclarativeCOS!")
>zforeach $zbind(words, "myIO:println")
Welcome
to
DeclarativeCOS!
Как это работает
Проект DeclarativeCOS использует глобал ^DeclarativeCOS для того чтобы сохранить информацию о методах, помеченных аннотацией @Declarative (declarativeName).
Каждая такой метод сохраняется в глобал в следующем виде:
set ^DeclarativeCOS(declarativeName) = $lb(className, classMethod)
Например, для функции io: println:
set ^DeclarativeCOS("io:println”) = $lb("DeclarativeCOS.IO”, "println”)
Каждый раз, когда используется функция io: println происходит поиск по глобалу, а потом функция $classmethod сделает вызов исходного метода (DeclarativeCOS.IO # println) на заданном значении.
Заключение
DeclarativeCOS это вклад в новый Caché ObjectScript. В тот самый язык, который действительно помогает своим разработчикам писать программы быстро, лаконично, просто и надежно. Добро пожаловать в критику, поддержку и мнения в комментарии под этим постом!)
Комментарии (6)
24 апреля 2017 в 12:32 (комментарий был изменён)
0↑
↓
Простите, пожалуйста, но про какой язык нельзя сказать, что он »действительно помогает своим разработчикам писать программы быстро, лаконично, просто и надежно»?P.S. А где монады?
24 апреля 2017 в 13:00 (комментарий был изменён)
0↑
↓
Brainfuck же.А если серьезно, примеров можно много привести: AppleScript, ассемблер, все языки, созданные во времена жестких ограничений по ресурсам.
24 апреля 2017 в 13:14
0↑
↓
Ну, всё же они (кроме Brainfuck) были созданы именно для помощи программистам — насколько это было возможно при имеющихся ресурсах.
24 апреля 2017 в 13:13
0↑
↓
Монад пока нет, при желании можно добавить.
24 апреля 2017 в 13:00 (комментарий был изменён)
0↑
↓
Простите, а можете объяснить, пожалуйста, в чем декларативность? Мне код кажется очень императивным? «Сделай а, потом б, потом в».То, что используются процедуры, а не классы еще ведь не делает код декларативным
24 апреля 2017 в 13:11
0↑
↓
Тонкое замечание) спасибо за вопрос!)Проект помогает скрыть слой циклов. Разработчику остается написать что нужно сделать с элементами коллекции. Всё остальное (по сути, только цикл) проект сделает сам.