Nemerle - Nemerle
Paradygmat | Wieloparadygmat : funkcjonalny , imperatywny , meta , zorientowany obiektowo |
---|---|
Zaprojektowany przez | Kamil Skalski, Michał Moskal, prof. Leszek Pacholski, Paweł Olszta na Uniwersytecie Wrocławskim |
Deweloper | JetBrains |
Po raz pierwszy pojawiły się | 2003 |
Wersja stabilna | 1.2.507,0 / 6 sierpnia 2016
|
Dyscyplina pisania | Wnioskowane , nominalne , statyczne , silne, |
Platforma | CLI |
Rozszerzenia nazw plików | .n |
Stronie internetowej | nemerle |
Główne wdrożenia | |
Nemerle | |
Wpływem | |
C# , Lisp , ML |
Nemerle to uniwersalny , wysokopoziomowy , statycznie typowany język programowania przeznaczony dla platform korzystających z infrastruktury Common Language Infrastructure ( .NET / Mono ). Oferuje funkcje funkcjonalne , obiektowe i imperatywne . Ma prostą składnię podobną do C# i potężny system metaprogramowania . W czerwcu 2012 roku, deweloperzy rdzeniowe nemerle zostali wynajęci przez czeski oprogramowanie Development Company JetBrains . Zespół koncentruje się na rozwijaniu Nitry, frameworka do wdrażania istniejących i nowych języków programowania. Ten framework będzie prawdopodobnie używany do tworzenia przyszłych wersji Nemerle.
Nazwa Nemerle pochodzi od arcymaga Nemmerle, postaci z powieści fantasy Czarnoksiężnik z Ziemiomorza autorstwa Ursuli K. Le Guin .
Cechy
Najbardziej godną uwagi cechą Nemerle jest możliwość mieszania stylów programowania, które są zorientowane obiektowo i funkcjonalne. Programy mogą być ustrukturyzowane przy użyciu pojęć obiektowych, takich jak klasy i przestrzenie nazw, podczas gdy metody mogą (opcjonalnie) być napisane w stylu funkcjonalnym. Inne godne uwagi cechy to:
- wnioskowanie o silnym typie
- elastyczny podsystem metaprogramowania (za pomocą makr )
- pełne wsparcie dla programowania obiektowego (OOP), w stylu C#, Java i C++
- pełne wsparcie dla programowania funkcjonalnego, w stylu ML , OCaml i Haskell , z następującymi funkcjami:
- funkcje wyższego rzędu
- dopasowanie wzorców
- typy algebraiczne
- funkcje lokalne
- krotki i typy anonimowe
- częściowe zastosowanie funkcji
System metaprogramowania pozwala na dużą rozszerzalność kompilatora , osadzanie języków specyficznych dla domeny , częściową ocenę i programowanie aspektowe , przyjmując podejście wysokiego poziomu, aby zdjąć jak najwięcej obciążeń ze strony programistów. Język łączy w sobie wszystkie standardowe cechy Common Language Infrastructure (CLI), w tym polimorfizm parametryczny , lambdy , metody rozszerzające itp. Dostęp do bibliotek zawartych w platformach .NET lub Mono jest tak prosty jak w C#.
Wnioskowanie o typie
def x = 1; // int
def myList = List(); // generic List[T], type T is deduced from the usage in the next line
myList.Add(x); // compiler deduces type of T as int making myList type of List[int]
Wszystko jest wyrażeniem
def x =
{ // similar to x = 3
def y = 1;
def z = 2;
y + z // this last statement is a block return value
};
def x =
if (DateTime.Now.DayOfWeek == DayOfWeek.Monday) // if, using, try are also expressions
"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); // exit block (x = true)
false // x = false
};
Krotki
def k = (1, "one"); // k : (int * string)
def (a, b) = k; // a = 1, b = "one"
Dopasowanie wzorca
def result = match (number)
{
| 0 => "zero"
| 1 => "one"
| x when x < 0 => "negative"
| _ => "more than one"
}
Dopasowanie typu z wiązaniem zmiennych:
def check (o : object) {
match (o)
{
| i is int => $"An int: $i"
| s is string => $"A string: $(s.ToUpper())"
| _ => "Object of another type"
}
}
Dopasowywanie wzorców krotek:
match (tuple)
{
| ( 42, _ ) => "42 on first position"
| ( _, 42 ) => "42 on second position"
| ( x, y ) => $"( $x, $y )"
}
Dopasowanie wyrażenia regularnego:
using Nemerle.Text;
regexp match (str) {
| "a+.*" => printf("a\n");
| @"(?<num : int>\d+)-\w+" => printf("%d\n", num + 3);
| "(?<name>(Ala|Kasia))? ma kota" =>
match (name)
{
| Some (n) => printf("%s\n", n)
| None => printf("noname?\n")
}
| _ => printf("default\n");
}
Typy funkcjonalne i funkcje lokalne
using System.Console; // classes and modules (static classes) can be put in namespaces
def next(x) { x + 1 }; // the type of x argument and other function arguments can be deduced from usage
def mult(x, y) { x * y };
def fibonacci(i)
{
| 0 => 0
| 1 => 1
| other => fibonacci(i - 1) + fibonacci(i - 2)
};
WriteLine(next(9)); // 10 similar to "Console.WriteLine(next(9));"
WriteLine(mult(2, 2)); // 4
WriteLine(fibonacci(10)); // 55
Warianty
Warianty (nazywane typami danych lub typami sum w SML i OCaml) to formy wyrażania danych kilku różnych rodzajów:
variant RgbColor {
| Red
| Yellow
| Green
| Different {
red : float;
green : float;
blue : float;
}
}
Metaprogramowanie
System makr Nemerle pozwala na tworzenie, analizowanie i modyfikowanie kodu programu podczas kompilacji. Makra mogą być używane w formie wywołania metody lub jako nowa konstrukcja języka. Wiele konstrukcji w języku jest zaimplementowanych przy użyciu makr (if, for, foreach, while, using itd.).
Przykład makra " if ":
macro @if (cond, e1, e2)
syntax ("if", "(", cond, ")", e1, Optional (";"), "else", e2)
{
/*
<[ ]> defines an area of quasi-quotation, the Nemerle compiler transforms the code in it
to an AST, such transformations are somewhat similar to an Expression compiling in C#
*/
<[
match ($cond : bool)
{
| true => $e1
| _ => $e2
}
]>
}
// using this macro in code:
def max = if (a > b) a else b;
// during a compile time the upper line will be transformed to this:
def max = match (a > b)
{
| true => a
| _ => b
}
IDE
Nemerle można zintegrować ze zintegrowanym środowiskiem programistycznym (IDE) Visual Studio 2008 . Posiada również w pełni darmowe IDE oparte na Visual Studio 2008 Shell (jak Visual Studio Express Editions ) i SharpDevelop ( link do kodu źródłowego wtyczki ).
Nemerle można również zintegrować z Visual Studio 2010 za pomocą dodatku.
Przykłady
Witaj świecie!
Tradycyjny Hello World! można zaimplementować w sposób bardziej podobny do C#:
class Hello
{
static Main () : void
{
System.Console.WriteLine ("Hello, world!");
}
}
lub prościej:
System.Console.WriteLine("Hello, world!");
Przykłady makr
Makra umożliwiają generowanie kodu wzorcowego z dodanymi kontrolami statycznymi wykonywanymi przez kompilator. Zmniejszają ilość kodu, który musi być napisany ręcznie, sprawiają, że generowanie kodu jest bezpieczniejsze i umożliwiają programom generowanie kodu z kontrolą kompilatora, jednocześnie utrzymując stosunkowo mały i czytelny kod źródłowy.
Formatowanie ciągów
Makro formatowania ciągów upraszcza manipulowanie zmiennymi za pomocą notacji $:
def s = $"The number is $i"; //insert the value of the variable i where $i is placed
def s = $"$x + $y = $(x+y)"; // $(...) can be used to make calculations or access members
Generowanie kodu deklaratywnego
StructuralEquality , Memoize , json i with to makra generujące kod w czasie kompilacji. Chociaż niektóre z nich ( StructuralEquality , Memoize ) mogą wyglądać jak atrybuty C#, podczas kompilacji zostaną zbadane przez kompilator i przekształcone w odpowiedni kod przy użyciu logiki predefiniowanej przez ich makra.
[StructuralEquality] // Implement IEquatable[Sample] .Net interface using by element comparison equality.
class Sample
{
[Memoize] // remember first evaluation result
public static SomeLongEvaluations() : int
{
MathLib.CalculateNthPrime(10000000)
}
[DependencyProperty] // WPF dependency property
public DependencyPropertySample { get; set; }
public static Main() : void
{
/* syntax macro "json" generates code:
JObject.Object([("a", JValue.Number(SomeLongEvaluations())), ("b", JValue.Number(SomeLongEvaluations() + 1))])
*/
def jObject = json { a: SomeLongEvaluations(); b: (SomeLongEvaluations() + 1)}
// object initialization macro "<-" is development of C# curly brackets object initialization
def k = Diagnostics.Process() <-
{
StartInfo <- // can init inner objects properties without ctor call
{
FileName = "calc.exe";
UseShellExecute = true;
}
Exited += () => WriteLine("Calc done"); // events and delegates
}
ReadLine();
}
}
Dostępność bazy danych
Używając makr Nemerle dla SQL możesz napisać:
ExecuteReaderLoop("SELECT firstname, lastname FROM employee WHERE firstname = $myparm", dbcon,
{
WriteLine ($"Name: $firstname $lastname")
});
zamiast
string sql = "SELECT firstname, lastname FROM employee WHERE firstname = :a";
using (NpgsqlCommand dbcmd = new NpgsqlCommand (sql, dbcon, dbtran))
{
dbcmd.Parameters.Add("a", myparm);
using (NpgsqlReader reader = dbcmd.ExecuteReader())
{
while(reader.Read())
{
var firstname = reader.GetString (0);
var lastname = reader.GetString (1);
Console.WriteLine ("Name: {0} {1}", firstname, lastname)
}
}
}
i nie jest to tylko ukrywanie niektórych operacji w bibliotece, ale dodatkowa praca wykonywana przez kompilator w celu zrozumienia ciągu zapytania, użytych tam zmiennych i kolumn zwróconych z bazy danych. Makro ExecuteReaderLoop wygeneruje kod w przybliżeniu równoważny temu, co trzeba by wpisać ręcznie. Co więcej, łączy się z bazą danych w czasie kompilacji, aby sprawdzić, czy zapytanie SQL naprawdę ma sens.
Nowe konstrukcje językowe
Za pomocą makr Nemerle możesz również wprowadzić do języka nową składnię:
macro ReverseFor (i, begin, body) syntax ("ford", "(", i, ";", begin, ")", body) { <[ for ($i = $begin; $i >= 0; $i--) $body ]> }
definiuje makro wprowadzające składnię ford (WYRAŻ ; WYRAŻ) WYRAŻ i może być używane jak
ford (i ; n) print (i);
Nemerle z ASP.NET
Nemerle może być osadzony bezpośrednio w ASP.NET :
<%@ Page Language="Nemerle" %>
<script runat="server">
Page_Load(_ : object, _ : EventArgs) : void {
Message.Text = $"You last accessed this page at: $(DateTime.Now)";
}
EnterBtn_Click(_ : object, _ : EventArgs) : void {
Message.Text = $"Hi $(Name.Text), welcome to ASP.NET!";
}
</script>
<html>
<body>
<form runat="server">
Please enter your name: <asp:TextBox ID="Name" runat="server" />
<asp:Button OnClick="EnterBtn_Click" Text="Enter" runat="server" />
<p><asp:Label ID="Message" runat="server" /></p>
</form>
</body>
</html>
...Lub przechowywane w osobnym pliku i wprowadzane w jednym wierszu:
<%@ Page Language="Nemerle" Src="test.n" Inherits="Test" %>
Wywołaj
Nemerle może korzystać z natywnych bibliotek platformy. Składnia jest bardzo podobna do C# i innych języków .NET. Oto najprostszy przykład:
using System;
using System.Runtime.InteropServices;
class PlatformInvokeTest
{
[DllImport("msvcrt.dll")]
public extern static puts(c : string) : int;
[DllImport("msvcrt.dll")]
internal extern static _flushall() : int;
public static Main() : void
{
_ = puts("Test");
_ = _flushall();
}
}
Bibliografia
Dalsza lektura
- Publikacje o Nemerle w RSDN Magazine, oficjalnym rosyjskim magazynie naukowym
-
Moskal, Michał (27 czerwca 2005). "Wnioskowanie o typie z odroczeniem" (PDF) . Instytut Informatyki Uniwersytetu Wrocławskiego. Cytowanie dziennika wymaga
|journal=
( pomoc ) - Prezentacja „Nemerle jest godna uwagi” Denisa Rystsova
- Artykuł „Niekonwencjonalne języki dla niekonwencjonalnych superkomputerów” Andrey Adinetz