Nemerle - 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 ; 18 lat temu ( 2003 )
Wersja stabilna
1.2.507,0 / 6 sierpnia 2016 ; 4 lata temu ( 2016-08-06 )
Dyscyplina pisania Wnioskowane , nominalne , statyczne , silne,
Platforma CLI
Rozszerzenia nazw plików .n
Stronie internetowej nemerle .org
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:

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"
}
Inne przykłady dopasowywania wzorców

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

Linki zewnętrzne