Nemerle — это универсальный , высокоуровневый , статически типизированный язык программирования , разработанный для платформ, использующих Common Language Infrastructure ( .NET / Mono ). Он предлагает функциональные , объектно-ориентированные , аспектно-ориентированные , рефлексивные и императивные возможности. Он имеет простой синтаксис, подобный C# , и мощную систему метапрограммирования .
В июне 2012 года основные разработчики Nemerle были наняты чешской компанией по разработке программного обеспечения JetBrains . Команда сосредоточилась на разработке Nitra, фреймворка для реализации существующих и новых языков программирования. [2] [3] [4] Как язык Nemerle, так и Nitra, по-видимому, были заброшены или прекращены JetBrains; Nitra не обновлялась его первоначальными создателями с 2017 года, и Nemerle теперь полностью поддерживается Russian Software Development Network, независимо от JetBrains, хотя никаких крупных обновлений пока не было выпущено, и разработка продвигается очень медленно. Ни Nemerle, ни Nitra не упоминались и не упоминались JetBrains в течение многих лет.
Немерле назван в честь архимага Неммерле, персонажа фэнтезийного романа «Волшебник Земноморья» Урсулы К. Ле Гуин .
Наиболее примечательной особенностью Nemerle является возможность смешивать стили программирования, которые являются объектно-ориентированными и функциональными. Программы могут быть структурированы с использованием объектно-ориентированных концепций, таких как классы и пространства имен, в то время как методы могут (опционально) быть написаны в функциональном стиле. Другие примечательные особенности включают в себя:
Система метапрограммирования обеспечивает большую расширяемость компилятора , встраивание доменно-специфичных языков , частичное вычисление и аспектно-ориентированное программирование , используя высокоуровневый подход для максимального снятия нагрузки с программистов. Язык объединяет все стандартные функции Common Language Infrastructure (CLI), включая параметрический полиморфизм , лямбды , методы расширения и т. д. Доступ к библиотекам, включенным в платформы .NET или Mono, так же прост, как и в C#.
def x = 1 ; // int def myList = List (); // generic List[T], тип T выводится из использования в следующей строке myList . Add ( x ); // компилятор выводит тип T как int, делая myList типом List[int]
def x = { // аналогично x = 3 def y = 1 ; def z = 2 ; y + z // этот последний оператор является возвращаемым значением блока }; def x = if ( DateTime . Now . DayOfWeek == DayOfWeek . Monday ) // if, using, try также являются выражениями "Monday" else "other day" ; def x = try int.Parse ( someString ) catch { | FormatException ( ) => 0 } ; def x = returnBlock : { foreach ( i in [ 1 , 2 , 3 ]) when ( i > 2 ) returnBlock ( true ); // выход из блока (x = true) ложь // x = ложь };
def k = ( 1 , "один" ); // k : (целое * строка) def ( a , b ) = k ; // a = 1, b = "один"
def result = match ( number ) { | 0 => "ноль" | 1 => "один" | x когда x < 0 => "отрицательно" | _ => "больше одного" }
Сопоставление типов с привязкой переменных:
def check ( o : object ) { match ( o ) { | i is int => $"An int: $i " | s is string => $"A string: $ ( s .T oUpper ()) " | _ => "Объект другого типа" } }
Сопоставление шаблонов кортежей:
match ( tuple ) { | ( 42 , _ ) => "42 на первой позиции" | ( _ , 42 ) => "42 на второй позиции" | ( x , y ) => $"( $x , $y )" }
Соответствие регулярному выражению:
с использованием Nemerle . Текст ; регулярное выражение match ( str ) { | "a+.*" => printf ( "a\n" ); | @"(?<num: int>\d+)-\w+" => printf ( "%d\n" , num + 3 ); | "(?<name>(Ala|Kasia))? ma kota" => match ( name ) { | Некоторые ( n ) => printf ( "%s\n" , n ) | Нет => printf ( "noname?\n" ) } | _ => printf ( "по умолчанию\n" ); }
using System.Console ; // классы и модули (статические классы) можно поместить в пространства имен def next ( x ) { x + 1 } ; // тип аргумента x и других аргументов функции можно вывести из использования def mult ( x , y ) { x * y }; def fibonacci ( i ) { | 0 => 0 | 1 => 1 | other => fibonacci ( i - 1 ) + fibonacci ( i - 2 ) }; WriteLine ( next ( 9 )); // 10 аналогично "Console.WriteLine(next(9));" WriteLine ( mult ( 2 , 2 )); // 4 WriteLine ( fibonacci ( 10 )); // 55
Варианты (называемые типами данных или типами сумм в SML и OCaml) представляют собой формы выражения данных нескольких различных видов:
вариант RgbColor { | Красный | Желтый | Зеленый | Разные { красный : плавающий ; зеленый : плавающий ; синий : плавающий ; } }
Система макросов Nemerle позволяет создавать, анализировать и изменять программный код во время компиляции. Макросы могут использоваться в форме вызова метода или как новая языковая конструкция. Многие конструкции в языке реализованы с помощью макросов (if, for, foreach, while, using и т. д.).
Пример макроса " if ":
макрос @if ( cond , e1 , e2 ) синтаксис ( "if" , "(" , cond , ")" , e1 , Необязательно ( ";" ), "else" , e2 ) { /* <[ ]> определяет область квазицитирования, компилятор Nemerle преобразует код в ней в AST, такие преобразования в некоторой степени похожи на компиляцию Expression в C# */ <[ match ( $cond : bool ) { | true => $e1 | _ => $e2 } ]> } // использование этого макроса в коде: def max = if ( a > b ) a else b ; // во время компиляции верхняя строка будет преобразована в это: def max = match ( a > b ) { | true => a | _ => b }
Подобно синтаксису без скобок, позже добавленному в Scala , Nemerle позволяет программисту опционально использовать чувствительный к пробелам синтаксис, основанный на правиле «вне игры» , аналогично Python .
Следующий фрагмент в фигурных скобках:
с использованием System.Console ; [Qux] класс FooBar { public static Main (): void { WriteLine ( "Привет" ) } static Foo ( x : int ): void { if ( x == 3 ) { def y = x * 42 ; Foo ( x ) } else { [x] . Map ( fun ( x ) { x * 2 }) } } статический бар (): int { def foo = 2 + 7 * 13 ; foo } }
можно переписать так:
с использованием System.Console ; [Qux] \ class FooBar public static Main (): void WriteLine ( "Привет" ) static Foo ( x : int ): void if ( x == 3 ) def y = x * 42 ; Foo ( x ) else [x] . Map ( fun ( x ) { x * 2 }) статический Bar (): int def foo = 2 + 7 * 13 foo
В частности, невозможно разбить выражения или альтернативные предложения в совпадениях, занимающих несколько строк, без использования обратной косой черты \
:
// Это не скомпилируется ...статический Bar (): int def foo = 2 + 7 * 13 foo совпадение ( s ) | "a" | "aa" => 1 | "b" | "bb" => 2 | _ => 0 // Но это будет: статический Bar (): int def foo = 2 \ + 7 \ * 13 foo совпадение ( s ) | "a" \ | "aa" => 1 | "b" \ | "bb" => 2 | _ => 0
Чтобы активировать этот синтаксис, пользователь должен добавить #pragma indent
в начало файла или использовать опцию компилятора -i
.
Nemerle можно интегрировать в интегрированную среду разработки (IDE) Visual Studio 2008. Также имеется полностью бесплатная IDE на основе Visual Studio 2008 Shell [5] (например, Visual Studio Express Editions ) и SharpDevelop (ссылка на исходный код плагина).
Nemerle также можно интегрировать в Visual Studio (до 2017 года) с помощью надстроек и расширений. [6]
Традиционную программу Hello World! можно реализовать в стиле, более похожем на C#:
class Hello { static Main () : void { System.Console.WriteLine ( " Привет , мир! " ) ; } }
или проще:
System.Console.WriteLine ( " Привет, мир ! " ) ;
Макросы позволяют генерировать шаблонный код с дополнительными статическими проверками, выполняемыми компилятором. Они уменьшают объем кода, который должен быть написан вручную, делают генерацию кода более безопасной и позволяют программам генерировать код с проверками компилятора, сохраняя при этом исходный код относительно небольшим и читаемым.
Макрос форматирования строк упрощает манипуляции с переменными в строках с помощью обозначения $:
def s = $"Число равно $i " ; //вставить значение переменной i, где находится $i def s = $" $x + $y = $ ( x + y ) " ; // $(...) можно использовать для выполнения вычислений или доступа к членам
StructuralEquality , Memoize , json и with — это макросы, которые генерируют код во время компиляции. Хотя некоторые из них ( StructuralEquality , Memoize ) могут выглядеть как атрибуты C#, во время компиляции они будут проверены компилятором и преобразованы в соответствующий код с использованием логики, предопределенной их макросами.
[StructuralEquality] // Реализуем интерфейс IEquatable[Sample].Net, используя равенство сравнения элементов. class Sample { [Memoize] // запоминаем результат первой оценки public static SomeLongEvaluations () : int { MathLib . CalculateNthPrime ( 10000000 ) } [DependencyProperty] // Свойство зависимости WPF public DependencyPropertySample { get ; set ; } public static Main () : void { /* макрос синтаксиса "json" генерирует код: JObject.Object([("a", JValue.Number(SomeLongEvaluations())), ("b", JValue.Number(SomeLongEvaluations() + 1))]) */ def jObject = json { a : SomeLongEvaluations (); b : ( SomeLongEvaluations () + 1 )} // макрос инициализации объекта "<-" является развитием инициализации объекта фигурными скобками C# def k = Diagnostics . Process () <- { StartInfo <- // можно инициализировать свойства внутренних объектов без вызова конструктора { FileName = "calc.exe" ; UseShellExecute = true ; } Exited += () => WriteLine ( "Calc done" ); // события и делегаты } ReadLine (); } }
Используя макросы Nemerle для SQL вы можете написать:
ExecuteReaderLoop ( "SELECT имя, фамилия ИЗ сотрудника, где имя = $myparm" , dbcon , { WriteLine ( $"Имя: $firstname $lastname " ) });
вместо
string sql = "SELECT имя, фамилия FROM employee WHERE имя = :a" ; using ( NpgsqlCommand dbcmd = new NpgsqlCommand ( sql , dbcon , dbtran )) { dbcmd . Параметры . Добавить ( "a" , myparm ); using ( NpgsqlReader reader = dbcmd . ExecuteReader ()) { while ( reader . Read ()) { var firstname = reader . GetString ( 0 ); var lastname = reader . GetString ( 1 ); Console . WriteLine ( "Имя: {0} {1}" , firstname , lastname ) } } }
и это не просто сокрытие некоторых операций в библиотеке, а дополнительная работа, выполняемая компилятором для понимания строки запроса, используемых там переменных и столбцов, возвращаемых из базы данных. Макрос ExecuteReaderLoop сгенерирует код, примерно эквивалентный тому, что вам пришлось бы набирать вручную. Более того, он подключается к базе данных во время компиляции, чтобы проверить, что ваш SQL-запрос действительно имеет смысл.
С помощью макросов Nemerle вы также можете ввести в язык новый синтаксис:
макрос ReverseFor ( i , begin , body ) синтаксис ( "ford" , "(" , i , ";" , begin , ")" , body ) { <[ for ( $i = $begin ; $i >= 0 ; $i --) $body ]> }
определяет макрос, представляющий синтаксис EXPR ford (EXPR ; EXPR) и может использоваться как
форд (я ; н) печать (я);
Nemerle можно встроить непосредственно в ASP.NET :
<%@ Язык страницы = "Nemerle" %> <script runat= "server" > Page_Load ( _ : object , _ : EventArgs ) : void { Message . Text = $"Вы последний раз посещали эту страницу: $(DateTime.Now)" ; } EnterBtn_Click ( _ : object , _ : EventArgs ) : void { Message . Text = $"Привет, $(Name.Text), добро пожаловать в ASP.NET!" ; } </скрипт><html> <body> <form runat= "server" > Введите свое имя : <asp:TextBox ID= "Name" runat= "server" /> <asp:Button OnClick= "EnterBtn_Click" Text= "Enter" runat= "server" /> <p><asp:Label ID= "Сообщение" runat= "сервер" /></p> </form> </body> </html>
...Или сохранить в отдельном файле и ввести одной строкой:
<%@ Язык страницы = "Nemerle" Источник = "test.n" Наследует = "Test" %>
Nemerle может использовать собственные библиотеки платформы. Синтаксис очень похож на C# и другие языки .NET. Вот простейший пример:
с использованием System ; с использованием System.Runtime.InteropServices ; class PlatformInvokeTest { [DllImport("msvcrt.dll")] public extern static puts ( c : string ) : int ; [DllImport("msvcrt.dll")] внутренний внешний статический _flushall () : int ; public static Main () : void { _ = puts ( "Тест" ); _ = _flushall (); } }
{{cite journal}}
: Цитировать журнал требует |journal=
( помощь )