109.160.203.89 (talk) No edit summary |
Use nemerle lexer for highlighting |
||
Line 45: | Line 45: | ||
===Type inference=== |
===Type inference=== |
||
<source lang=" |
<source lang="nemerle"> |
||
def x = 1; // int |
def x = 1; // int |
||
def myList = List(); // generic List[T], type T is deduced from the usage in the next line |
def myList = List(); // generic List[T], type T is deduced from the usage in the next line |
||
Line 52: | Line 52: | ||
===Everything is an expression=== |
===Everything is an expression=== |
||
<source lang=" |
<source lang="nemerle"> |
||
def x = |
def x = |
||
{ // similar to x = 3 |
{ // similar to x = 3 |
||
Line 80: | Line 80: | ||
===Tuples=== |
===Tuples=== |
||
<source lang=" |
<source lang="nemerle"> |
||
def k = (1, "one"); // k : (int * string) |
def k = (1, "one"); // k : (int * string) |
||
def (a, b) = k; // a = 1, b = "one" |
def (a, b) = k; // a = 1, b = "one" |
||
Line 86: | Line 86: | ||
===Pattern matching=== |
===Pattern matching=== |
||
<source lang=" |
<source lang="nemerle"> |
||
def result = match (number) |
def result = match (number) |
||
{ |
{ |
||
Line 98: | Line 98: | ||
{{hidden|Other pattern matching examples|style = border:1px dashed gray;| |
{{hidden|Other pattern matching examples|style = border:1px dashed gray;| |
||
Type matching with variable binding: |
Type matching with variable binding: |
||
<source lang=" |
<source lang="nemerle"> |
||
def check (o : object) { |
def check (o : object) { |
||
match (o) |
match (o) |
||
Line 109: | Line 109: | ||
</source> |
</source> |
||
Tuple pattern matching: |
Tuple pattern matching: |
||
<source lang=" |
<source lang="nemerle"> |
||
match (tuple) |
match (tuple) |
||
{ |
{ |
||
Line 118: | Line 118: | ||
</source> |
</source> |
||
Regexp matching: |
Regexp matching: |
||
<source lang=" |
<source lang="nemerle"> |
||
using Nemerle.Text; |
using Nemerle.Text; |
||
regexp match (str) { |
regexp match (str) { |
||
Line 136: | Line 136: | ||
===Functional types and local functions=== |
===Functional types and local functions=== |
||
<source lang=" |
<source lang="nemerle"> |
||
using System.Console; // classes and modules (static classes) can be put in namespaces |
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 next(x) { x + 1 }; // the type of x argument and other function arguments can be deduced from usage |
||
Line 156: | Line 156: | ||
=== Variants === |
=== Variants === |
||
[[Sum type|Variants]] (called data types or sum types in SML and OCaml) are forms of expressing data of several different kinds: |
[[Sum type|Variants]] (called data types or sum types in SML and OCaml) are forms of expressing data of several different kinds: |
||
<source lang=" |
<source lang="nemerle"> |
||
variant RgbColor{ |
variant RgbColor{ |
||
| Red |
| Red |
||
Line 173: | Line 173: | ||
"'''if'''" macro example: |
"'''if'''" macro example: |
||
<source lang=" |
<source lang="nemerle"> |
||
macro @if (cond, e1, e2) |
macro @if (cond, e1, e2) |
||
syntax ("if", "(", cond, ")", e1, Optional (";"), "else", e2) |
syntax ("if", "(", cond, ")", e1, Optional (";"), "else", e2) |
||
Line 210: | Line 210: | ||
The traditional [[Hello world program|"Hello World!"]] can be implemented in a more C#-like fashion: |
The traditional [[Hello world program|"Hello World!"]] can be implemented in a more C#-like fashion: |
||
<source lang=" |
<source lang="nemerle"> |
||
class Hello |
class Hello |
||
{ |
{ |
||
Line 222: | Line 222: | ||
or more simply: |
or more simply: |
||
<source lang=" |
<source lang="nemerle"> |
||
System.Console.WriteLine("Hello, world!"); |
System.Console.WriteLine("Hello, world!"); |
||
</source> |
</source> |
||
Line 231: | Line 231: | ||
====String formatting ==== |
====String formatting ==== |
||
The string formatting macro simplifies variables to string manipulations using $ notation: |
The string formatting macro simplifies variables to string manipulations using $ notation: |
||
<source lang=" |
<source lang="nemerle"> |
||
def s = $"The number is $i"; //insert the value of the variable i where $i is placed |
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 |
def s = $"$x + $y = $(x+y)"; // $(...) can be used to make calculations or access members |
||
Line 241: | Line 241: | ||
Although some of them (''StructuralEquality'', ''Memoize'') can look like C# attributes, during compile time they will be examined by the compiler and transformed to appropriate code using logic predefined by their macros. |
Although some of them (''StructuralEquality'', ''Memoize'') can look like C# attributes, during compile time they will be examined by the compiler and transformed to appropriate code using logic predefined by their macros. |
||
<source lang=" |
<source lang="nemerle"> |
||
[StructuralEquality] // Implement IEquatable[Sample] .Net interface using by element comparison equality. |
[StructuralEquality] // Implement IEquatable[Sample] .Net interface using by element comparison equality. |
||
class Sample |
class Sample |
||
Line 280: | Line 280: | ||
Using Nemerle macros for [[SQL]] you can write: |
Using Nemerle macros for [[SQL]] you can write: |
||
<source lang=" |
<source lang="nemerle"> |
||
ExecuteReaderLoop("SELECT firstname, lastname FROM employee WHERE firstname = $myparm", dbcon, |
ExecuteReaderLoop("SELECT firstname, lastname FROM employee WHERE firstname = $myparm", dbcon, |
||
{ |
{ |
||
Line 289: | Line 289: | ||
instead of |
instead of |
||
<source lang=" |
<source lang="nemerle"> |
||
string sql = "SELECT firstname, lastname FROM employee WHERE firstname = :a"; |
string sql = "SELECT firstname, lastname FROM employee WHERE firstname = :a"; |
||
using (NpgsqlCommand dbcmd = new NpgsqlCommand (sql, dbcon, dbtran)) |
using (NpgsqlCommand dbcmd = new NpgsqlCommand (sql, dbcon, dbtran)) |
Revision as of 21:46, 25 June 2015
Paradigm | multi-paradigm: metaprogramming, functional, object-oriented, imperative |
---|---|
Designed by | Kamil Skalski, Michał Moskal, Prof. Leszek Pacholski and Paweł Olszta at Wrocław University |
First appeared | 2003 |
Stable release | 1.0.0
/ May 13, 2011 |
Typing discipline | static, strong, inferred, nominal |
Platform | CLI (.Net & Mono) |
Filename extensions | .n |
Website | http://nemerle.org |
Major implementations | |
Nemerle | |
Influenced by | |
C#, ML, Lisp |
Nemerle is a general-purpose high-level statically typed programming language designed for platforms using the Common Language Infrastructure (.NET/Mono). It offers functional, object-oriented and imperative features. It has a simple C#-like syntax and a powerful metaprogramming system. In June 2012, the core developers of Nemerle were hired by the Czech software development company JetBrains. The team is focusing on the development of Nitra; a framework for implementing new and existing programming languages. This framework will likely be used to create future versions of Nemerle.[1][2][3]
The language was named after the Archmage Nemmerle, a character in the fantasy novel A Wizard of Earthsea by Ursula K. Le Guin.
Features
Nemerle's most notable feature is the ability to mix object oriented and functional styles of programming. Programs may be structured using object oriented concepts such as classes and namespaces, while methods can (optionally) be written in a functional style. Other notable features include:
- strong type inference
- a flexible metaprogramming subsystem (using macros)
- full support for OOP (in the style of C#, Java, and C++)
- full support for functional programming (in the style of ML, OCaml, Haskell) with the following features:
- higher-order functions
- pattern matching
- algebraic types
- local functions
- tuples and anonymous types
- partial application of functions
The metaprogramming system allows for a great deal of compiler extensibility, embedding of domain specific languages, partial evaluation, and aspect-oriented programming, taking a high-level approach to lift as much of the burden from the programmer as possible. The language combines all CLI standard features, including parametric polymorphism, lambdas, extension methods etc. Accessing the libraries included in the .NET or Mono platforms is as easy as in C#.
Type inference
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]
Everything is an expression
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
};
Tuples
def k = (1, "one"); // k : (int * string)
def (a, b) = k; // a = 1, b = "one"
Pattern matching
def result = match (number)
{
| 0 => "zero"
| 1 => "one"
| x when x < 0 => "negative"
| _ => "more than one"
}
Type matching with variable binding:
def check (o : object) {
match (o)
{
| i is int => $"An int: $i"
| s is string => $"A string: $(s.ToUpper())"
| _ => "Object of another type"
}
}
Tuple pattern matching:
match (tuple)
{
| ( 42, _ ) => "42 on first position"
| ( _, 42 ) => "42 on second position"
| ( x, y ) => $"( $x, $y )"
}
Regexp matching:
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");
}
Functional types and local functions
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
Variants
Variants (called data types or sum types in SML and OCaml) are forms of expressing data of several different kinds:
variant RgbColor{
| Red
| Yellow
| Green
| Different {
red : float;
green : float;
blue : float;
}
}
Metaprogramming
Nemerle's macro system allows for the creation, analysis, and modification of a program's code during the compilation process. Macros can be used in the form of a method call or as a new language construct. Many constructs within the language were implemented using macros (if, for, foreach, while, using etc.).
"if" macro example:
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 tree, 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 the following:
def max = match (a > b)
{
| true => a
| _ => b
}
IDE
Nemerle can be integrated into Visual Studio 2008. It also has a completely free IDE based on Visual Studio 2008 Shell[4] (like Visual Studio Express Editions) and SharpDevelop (link to plugin source code).
Nemerle can be also integrated into Visual Studio 2010 using the add-in.
Examples
Hello, World!
The traditional "Hello World!" can be implemented in a more C#-like fashion:
class Hello
{
static Main () : void
{
System.Console.WriteLine ("Hello, world!");
}
}
or more simply:
System.Console.WriteLine("Hello, world!");
Examples of macros
Macros allow generation of boilerplate code with additional static checks performed by the compiler. They reduce the amount of code that must be written by hand, make code generation safer, and allow for programmatic generation of code with compiler checks, while keeping source code relatively small and readable.
String formatting
The string formatting macro simplifies variables to string manipulations using $ notation:
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
Declarative code generation
StructuralEquality, Memoize, json, and with are macros which generate code in compile time. Although some of them (StructuralEquality, Memoize) can look like C# attributes, during compile time they will be examined by the compiler and transformed to appropriate code using logic predefined by their macros.
[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();
}
}
Database accessibility
Using Nemerle macros for SQL you can write:
ExecuteReaderLoop("SELECT firstname, lastname FROM employee WHERE firstname = $myparm", dbcon,
{
WriteLine ($"Name: $firstname $lastname")
});
instead of
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)
}
}
}
and this is not just hiding some operations in a library, but additional work performed by the compiler to understand the query string, the variables used there, and the columns returned from the database. The ExecuteReaderLoop macro will generate code roughly equivalent to what you would have to type manually. Moreover, it connects to the database at compilation time to check that your SQL query really makes sense.
New language constructs
With Nemerle macros you can also introduce some new syntax into the language:
macro ReverseFor (i, begin, body) syntax ("ford", "(", i, ";", begin, ")", body) { <[ for ($i = $begin; $i >= 0; $i--) $body ]> }
defines a macro introducing the ford (EXPR ; EXPR) EXPR syntax and can be used like
ford (i ; n) print (i);
Nemerle with ASP.NET
Nemerle can be either embedded directly into 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>
...Or stored in a separate file and entered with a single line:
<%@ Page Language="Nemerle" Src="test.n" Inherits="Test" %>
PInvoke
Nemerle can take advantage of native platform libraries. The syntax is very similar to C#'s and other .NET languages. Here is the simplest example:
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();
}
}
References
- ^ "Twitter / orangy: We've decided to bring Nemerle". Twitter.com. Retrieved 2013-09-05.
- ^ "JetBrains .NET Tools Blog » JetBrains and Nemerle". Blogs.jetbrains.com. 2012-06-27. Retrieved 2013-09-05.
- ^ "Google Discussiegroepen". Groups.google.com. Retrieved 2013-09-05.
- ^ Nemerle Studio Microsoft Setup Installer can be installed after installation of Visual Studio Shell 2008 Isolated
Further reading
- Publications about Nemerle in RSDN Magazine, Russian official science magazine
- Moskal, Michał (27 June 2005). "Type Inference with Deferral" (PDF). Institute of Computer Science, University of Wrocław.
{{cite journal}}
: Cite journal requires|journal=
(help) - Presentation "Nemerle is notable" by Denis Rystsov
- Article "Unconventional languages for unconventional supercomputers" by Andrey Adinetz