Nemerle: Difference between revisions
No edit summary |
Added in the list of statically typed programming languages (as described in 'Typing discipline'). |
||
(18 intermediate revisions by 15 users not shown) | |||
Line 1: | Line 1: | ||
{{Short description|Programming language}} |
|||
{{multiple issues| |
|||
{{lead too short|date=January 2013}} |
|||
{{manual|date=January 2013}} |
|||
{{Cleanup reorganize|date=February 2018}} |
|||
}} |
|||
{{Infobox programming language |
{{Infobox programming language |
||
|name = Nemerle |
|name = Nemerle |
||
|logo = |
|logo = |
||
|paradigm = [[ |
|paradigm = [[Multi-paradigm programming language|Multi-paradigm]]: [[aspect-oriented programming|aspect-oriented]], [[event-driven programming|event-driven]], [[functional programming|functional]], [[generic programming|generic]], [[imperative programming|imperative]], [[metaprogramming|meta]], [[object-oriented programming|object-oriented]], [[reflective programming|reflective]] |
||
|family = [[C Sharp (programming language)|C#]] |
|||
|designers = Kamil Skalski, Michał Moskal, Prof. Leszek Pacholski, Paweł Olszta at [[Wrocław University]] |
|designers = Kamil Skalski, Michał Moskal, Prof. Leszek Pacholski, Paweł Olszta at [[Wrocław University]] |
||
|developer = [[JetBrains]] |
|developer = [[JetBrains]] (formerly) <br /> RSDN |
||
|released = {{Start date and age|2003}} |
|released = {{Start date and age|2003}} |
||
|latest release version = 1.2.507.0<ref>[http://nemerle.org/Downloads Nemerle 1.2.507.0]</ref> |
|latest release version = 1.2.507.0<ref>[http://nemerle.org/Downloads Nemerle 1.2.507.0]</ref> |
||
|latest release date = {{Start date and age|2016|8|6|df=yes}} |
|latest release date = {{Start date and age|2016|8|6|df=yes}} |
||
|typing = [[Type |
|typing = [[Type inference|Inferred]], [[Nominal type system|nominal]], [[type system|static]], [[strong and weak typing|strong]] |
||
|implementations = Nemerle |
|implementations = Nemerle |
||
|dialects = |
|dialects = |
||
|influenced_by = [[C Sharp (programming language)|C#]], [[ |
|influenced_by = [[C Sharp (programming language)|C#]], [[Lisp (programming language)|Lisp]], [[ML (programming language)|ML]] |
||
|influenced = |
|influenced = |
||
|platform = [[Common Language Infrastructure|CLI]] |
|platform = [[Common Language Infrastructure|CLI]] |
||
|file ext = .n |
|file ext = .n |
||
|website = {{URL|nemerle.org}} |
|website = {{URL|nemerle.org}} |
||
}} |
}} |
||
'''Nemerle''' is a [[general-purpose programming language|general-purpose]] [[High-level programming language|high-level]] [[static typing|statically typed]] [[programming language]] designed for platforms using the [[Common Language Infrastructure]] ([[.NET Framework|.NET]]/[[Mono (software)|Mono]]). It offers [[functional programming|functional]], [[object-oriented]] |
'''Nemerle''' is a [[general-purpose programming language|general-purpose]], [[High-level programming language|high-level]], [[static typing|statically typed]] [[programming language]] designed for platforms using the [[Common Language Infrastructure]] ([[.NET Framework|.NET]]/[[Mono (software)|Mono]]). It offers [[functional programming|functional]], [[object-oriented]], [[aspect-oriented programming|aspect-oriented]], [[reflective programming|reflective]] and [[imperative programming|imperative]] features. It has a simple [[C Sharp (programming language)|C#]]-like syntax and a powerful [[metaprogramming]] system. |
||
In June 2012, the core developers of Nemerle were hired by the [[Czech Republic|Czech]] [[software]] development company [[JetBrains]]. The team was focusing on developing Nitra, a framework to implement extant and new programming languages.<ref>{{cite web|url=https://twitter.com/orangy/status/216127804482404352 |title=Twitter / orangy: We've decided to bring Nemerle |publisher=Twitter.com |access-date=2013-09-05}}</ref><ref>{{cite web|url=http://blogs.jetbrains.com/dotnet/2012/06/jetbrains-and-nemerle/ |title=JetBrains .NET Tools Blog » JetBrains and Nemerle |publisher=Blogs.jetbrains.com |date=2012-06-27 |access-date=2013-09-05}}</ref><ref>{{cite web|url=https://groups.google.com/forum/#!topic/nemerle-en/LKkEcftHF9I |title=Google Discussiegroepen |access-date=2013-09-05}}</ref> Both the Nemerle language and Nitra have seemingly been abandoned or discontinued by JetBrains; Nitra has not been updated by its original creators since 2017 and Nemerle is now maintained entirely by the Russian Software Development Network, independently from JetBrains, although no major updates have been released yet and development is progressing very slowly. Neither Nemerle, nor Nitra have been mentioned or referenced by JetBrains for years. |
|||
Nemerle is named after the Archmage Nemmerle, a character in the fantasy novel ''[[A Wizard of Earthsea]]'' by [[Ursula K. Le Guin]]. |
Nemerle is named after the Archmage Nemmerle, a character in the fantasy novel ''[[A Wizard of Earthsea]]'' by [[Ursula K. Le Guin]]. |
||
Line 32: | Line 30: | ||
Nemerle's most notable feature is the ability to mix styles of programming that are [[object-oriented]] and functional. 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: |
Nemerle's most notable feature is the ability to mix styles of programming that are [[object-oriented]] and functional. 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]] |
* strong [[type inference]] |
||
* a flexible metaprogramming subsystem (using macros) |
* a flexible metaprogramming subsystem (using [[Macro (computer science)|macros]]) |
||
* full support for [[object-oriented programming]] (OOP), in the style of C#, [[Java (programming language)|Java]], and [[C++]] |
* full support for [[object-oriented programming]] (OOP), in the style of C#, [[Java (programming language)|Java]], and [[C++]] |
||
* full support for functional programming, in the style of [[ML (programming language)|ML]], [[OCaml]], and [[Haskell (programming language)|Haskell]], with these features: |
* full support for functional programming, in the style of [[ML (programming language)|ML]], [[OCaml]], and [[Haskell (programming language)|Haskell]], with these features: |
||
** [[higher-order |
** [[higher-order function]]s |
||
** [[pattern matching]] |
** [[pattern matching]] |
||
** [[algebraic types]] |
** [[algebraic types]] |
||
Line 42: | Line 40: | ||
** [[partial application]] of functions |
** [[partial application]] of functions |
||
The metaprogramming system allows for great [[compiler]] extensibility, embedding [[domain-specific language]]s, [[partial evaluation]], and [[aspect-oriented programming]], taking a [[High-level programming language|high-level]] approach to lift as much of the burden as possible from programmers. The language combines all [[Common Language Infrastructure]] (CLI) standard features, including [[ |
The metaprogramming system allows for great [[compiler]] extensibility, embedding [[domain-specific language]]s, [[partial evaluation]], and [[aspect-oriented programming]], taking a [[High-level programming language|high-level]] approach to lift as much of the burden as possible from programmers. The language combines all [[Common Language Infrastructure]] (CLI) standard features, including [[parametric polymorphism]], [[Anonymous function|lambdas]], [[extension method]]s etc. Accessing the libraries included in the .NET or Mono platforms is as easy as in C#. |
||
===Type inference=== |
===Type inference=== |
||
< |
<syntaxhighlight 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 |
||
myList.Add(x); // compiler deduces type of T as int making myList type of List[int] |
myList.Add(x); // compiler deduces type of T as int making myList type of List[int] |
||
</syntaxhighlight> |
|||
</source> |
|||
===Everything is an expression=== |
===Everything is an expression=== |
||
< |
<syntaxhighlight lang="nemerle"> |
||
def x = |
def x = |
||
{ // similar to x = 3 |
{ // similar to x = 3 |
||
Line 61: | Line 59: | ||
def x = |
def x = |
||
if (DateTime.Now.DayOfWeek == DayOfWeek.Monday) // if, using, try |
if (DateTime.Now.DayOfWeek == DayOfWeek.Monday) // if, using, try are also expressions |
||
"Monday" |
"Monday" |
||
else |
else |
||
Line 77: | Line 75: | ||
false // x = false |
false // x = false |
||
}; |
}; |
||
</syntaxhighlight> |
|||
</source> |
|||
===Tuples=== |
===Tuples=== |
||
< |
<syntaxhighlight 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" |
||
</syntaxhighlight> |
|||
</source> |
|||
===Pattern matching=== |
===Pattern matching=== |
||
< |
<syntaxhighlight lang="nemerle"> |
||
def result = match (number) |
def result = match (number) |
||
{ |
{ |
||
Line 94: | Line 92: | ||
| _ => "more than one" |
| _ => "more than one" |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
{{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: |
||
< |
<syntaxhighlight lang="nemerle"> |
||
def check (o : object) { |
def check (o : object) { |
||
match (o) |
match (o) |
||
Line 107: | Line 105: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
Tuple pattern matching: |
Tuple pattern matching: |
||
< |
<syntaxhighlight lang="nemerle"> |
||
match (tuple) |
match (tuple) |
||
{ |
{ |
||
Line 116: | Line 114: | ||
| ( x, y ) => $"( $x, $y )" |
| ( x, y ) => $"( $x, $y )" |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
Regexp matching: |
Regexp matching: |
||
< |
<syntaxhighlight lang="nemerle"> |
||
using Nemerle.Text; |
using Nemerle.Text; |
||
regexp match (str) { |
regexp match (str) { |
||
Line 132: | Line 130: | ||
| _ => printf("default\n"); |
| _ => printf("default\n"); |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
}} |
}} |
||
===Functional types and local functions=== |
===Functional types and local functions=== |
||
< |
<syntaxhighlight 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 152: | Line 150: | ||
WriteLine(mult(2, 2)); // 4 |
WriteLine(mult(2, 2)); // 4 |
||
WriteLine(fibonacci(10)); // 55 |
WriteLine(fibonacci(10)); // 55 |
||
</syntaxhighlight> |
|||
</source> |
|||
=== 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: |
||
< |
<syntaxhighlight lang="nemerle"> |
||
variant RgbColor { |
variant RgbColor { |
||
| Red |
| Red |
||
Line 167: | Line 165: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
===Metaprogramming=== |
===Metaprogramming=== |
||
Line 173: | Line 171: | ||
"'''if'''" macro example: |
"'''if'''" macro example: |
||
< |
<syntaxhighlight 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 198: | Line 196: | ||
| _ => b |
| _ => b |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
=== Braceless syntax === |
|||
Similarly to the braceless syntax later added to [[Scala (programming language)|Scala]], Nemerle allows the programmer to optionally use a whitespace-sensitive syntax based on the [[off-side rule]], similarly to [[Python (programming language)|Python]]. |
|||
The following curly-brace snippet: |
|||
<syntaxhighlight lang = "nemerle"> |
|||
using System.Console; |
|||
[Qux] |
|||
class FooBar { |
|||
public static Main(): void { |
|||
WriteLine("Hello") |
|||
} |
|||
static Foo (x: int): void { |
|||
if (x == 3) { |
|||
def y = x * 42; |
|||
Foo (x) |
|||
} else { |
|||
[x].Map (fun (x) { |
|||
x * 2 |
|||
}) |
|||
} |
|||
} |
|||
static Bar(): int { |
|||
def foo = 2 + 7 * 13; |
|||
foo |
|||
} |
|||
} |
|||
</syntaxhighlight> |
|||
could be rewritten as: |
|||
<syntaxhighlight lang = "nemerle"> |
|||
using System.Console; |
|||
[Qux] \ |
|||
class FooBar |
|||
public static Main(): void |
|||
WriteLine("Hello") |
|||
static Foo (x: int): void |
|||
if (x == 3) |
|||
def y = x * 42; |
|||
Foo (x) |
|||
else |
|||
[x].Map (fun (x) { |
|||
x * 2 |
|||
}) |
|||
static Bar(): int |
|||
def foo = 2 + 7 * 13 |
|||
foo |
|||
</syntaxhighlight> |
|||
Notably, it is not possible to break expressions or alternative clauses in matches over multiple lines without using a backslash <code>\</code>: |
|||
<syntaxhighlight lang = "nemerle"> |
|||
// This will not compile ... |
|||
static Bar(): int |
|||
def foo = 2 |
|||
+ 7 |
|||
* 13 |
|||
foo |
|||
match (s) |
|||
| "a" |
|||
| "aa" => 1 |
|||
| "b" |
|||
| "bb" => 2 |
|||
| _ => 0 |
|||
// But this will: |
|||
static Bar(): int |
|||
def foo = 2 \ |
|||
+ 7 \ |
|||
* 13 |
|||
foo |
|||
match (s) |
|||
| "a" \ |
|||
| "aa" => 1 |
|||
| "b" \ |
|||
| "bb" => 2 |
|||
| _ => 0 |
|||
</syntaxhighlight> |
|||
In order to activate this syntax, the user must add <code>#pragma indent</code> to the top of the file or use the compiler option <code>-i</code>. |
|||
== IDE == |
== IDE == |
||
Nemerle can be integrated into the [[integrated development environment]] (IDE) [[Visual Studio 2008]]. It also has a fully free IDE based on Visual Studio 2008 Shell<ref>[https://code.google.com/p/nemerle/downloads/list Nemerle Studio Microsoft Setup Installer] can be installed after installing [http://www.microsoft.com/downloads/en/details.aspx?FamilyID=aca38719-f449-4937-9bac-45a9f8a73822&displaylang=en Visual Studio Shell 2008 Isolated]</ref> (like [[Visual Studio Express Edition]]s) and [[SharpDevelop]] ([https://code.google.com/p/nemerle/source/browse/#svn%2Fnemerle%2Ftrunk%2Fsnippets%2Fsharpdevelop link to plugin source code]). |
Nemerle can be integrated into the [[integrated development environment]] (IDE) [[Visual Studio 2008]]. It also has a fully free IDE based on Visual Studio 2008 Shell<ref>[https://code.google.com/p/nemerle/downloads/list Nemerle Studio Microsoft Setup Installer] can be installed after installing [http://www.microsoft.com/downloads/en/details.aspx?FamilyID=aca38719-f449-4937-9bac-45a9f8a73822&displaylang=en Visual Studio Shell 2008 Isolated]</ref> (like [[Visual Studio Express Edition]]s) and [[SharpDevelop]] ([https://code.google.com/p/nemerle/source/browse/#svn%2Fnemerle%2Ftrunk%2Fsnippets%2Fsharpdevelop link to plugin source code]). |
||
Nemerle can be also integrated into [[Visual Studio |
Nemerle can be also integrated into [[Visual Studio]] (up until 2017) using add-ins and extensions.<ref>[http://visualstudiogallery.msdn.microsoft.com/5d93dc0a-0ce9-4b97-970c-ab1993eb934a Visual Studio 2010 add-in]</ref> |
||
==Examples== |
==Examples== |
||
===Hello, World!=== |
===Hello, World!=== |
||
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: |
||
< |
<syntaxhighlight lang="nemerle"> |
||
class Hello |
class Hello |
||
{ |
{ |
||
Line 218: | Line 311: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
or more simply: |
or more simply: |
||
< |
<syntaxhighlight lang="nemerle"> |
||
System.Console.WriteLine("Hello, world!"); |
System.Console.WriteLine("Hello, world!"); |
||
</syntaxhighlight> |
|||
</source> |
|||
===Examples of macros=== |
===Examples of macros=== |
||
Line 231: | Line 324: | ||
====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: |
||
< |
<syntaxhighlight 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 |
||
</syntaxhighlight> |
|||
</source> |
|||
====Declarative code generation==== |
====Declarative code generation==== |
||
Line 240: | Line 333: | ||
''StructuralEquality'', ''Memoize'', ''json'', and ''with'' are macros which generate code in compile time. Though some of them (''StructuralEquality'', ''Memoize'') can look like C# attributes, during compiling, they will be examined by the compiler and transformed to appropriate code using logic predefined by their macros. |
''StructuralEquality'', ''Memoize'', ''json'', and ''with'' are macros which generate code in compile time. Though some of them (''StructuralEquality'', ''Memoize'') can look like C# attributes, during compiling, they will be examined by the compiler and transformed to appropriate code using logic predefined by their macros. |
||
< |
<syntaxhighlight 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 273: | Line 366: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
====Database accessibility==== |
====Database accessibility==== |
||
Line 279: | Line 372: | ||
Using Nemerle macros for [[SQL]] you can write: |
Using Nemerle macros for [[SQL]] you can write: |
||
< |
<syntaxhighlight lang="nemerle"> |
||
ExecuteReaderLoop("SELECT firstname, lastname FROM employee WHERE firstname = $myparm", dbcon, |
ExecuteReaderLoop("SELECT firstname, lastname FROM employee WHERE firstname = $myparm", dbcon, |
||
{ |
{ |
||
WriteLine ($"Name: $firstname $lastname") |
WriteLine ($"Name: $firstname $lastname") |
||
}); |
}); |
||
</syntaxhighlight> |
|||
</source> |
|||
instead of |
instead of |
||
< |
<syntaxhighlight 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)) |
||
Line 304: | Line 397: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
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. |
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. |
||
Line 311: | Line 404: | ||
With Nemerle macros you can also introduce some new syntax into the language: |
With Nemerle macros you can also introduce some new syntax into the language: |
||
<syntaxhighlight lang = "nemerle"> |
|||
'''macro''' ReverseFor (i, begin, body) |
|||
macro ReverseFor (i, begin, body) |
|||
syntax("ford", "(", i, ";", begin, ")", body) |
|||
{ |
|||
{ |
|||
<[ for ($i = $begin; $i >= 0; $i--) $body ]> |
<[ for ($i = $begin; $i >= 0; $i--) $body ]> |
||
} |
|||
</syntaxhighlight> |
|||
defines a macro introducing the |
defines a macro introducing the {{mono|ford (EXPR ; EXPR) EXPR}} syntax and can be used like |
||
ford (i ; n) print (i); |
ford (i ; n) print (i); |
||
Line 323: | Line 418: | ||
===Nemerle with ASP.NET=== |
===Nemerle with ASP.NET=== |
||
Nemerle can be either embedded directly into [[ASP.NET]]: |
Nemerle can be either embedded directly into [[ASP.NET]]: |
||
< |
<syntaxhighlight lang="aspx-cs"> |
||
<%@ Page Language="Nemerle" %> |
<%@ Page Language="Nemerle" %> |
||
<script runat="server"> |
<script runat="server"> |
||
Line 347: | Line 442: | ||
</body> |
</body> |
||
</html> |
</html> |
||
</syntaxhighlight> |
|||
</source> |
|||
...Or stored in a separate file and entered with a single line: |
...Or stored in a separate file and entered with a single line: |
||
< |
<syntaxhighlight lang="aspx-cs"> |
||
<%@ Page Language="Nemerle" Src="test.n" Inherits="Test" %> |
<%@ Page Language="Nemerle" Src="test.n" Inherits="Test" %> |
||
</syntaxhighlight> |
|||
</source> |
|||
===PInvoke=== |
===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: |
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: |
||
< |
<syntaxhighlight lang="csharp"> |
||
using System; |
using System; |
||
using System.Runtime.InteropServices; |
using System.Runtime.InteropServices; |
||
Line 374: | Line 469: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</source> |
|||
==References== |
==References== |
||
Line 395: | Line 490: | ||
{{Common Language Infrastructure}} |
{{Common Language Infrastructure}} |
||
{{DEFAULTSORT:Nemerle}} |
|||
[[Category:Programming languages]] |
[[Category:Programming languages]] |
||
[[Category:Procedural programming languages]] |
[[Category:Procedural programming languages]] |
||
[[Category:.NET programming languages]] |
[[Category:.NET programming languages]] |
||
[[Category:Object-oriented programming languages]] |
[[Category:Object-oriented programming languages]] |
||
[[Category:ML programming language family]] |
|||
[[Category:Programming languages created in 2003]] |
[[Category:Programming languages created in 2003]] |
||
[[Category:2003 software]] |
[[Category:2003 software]] |
||
[[Category:High-level programming languages]] |
[[Category:High-level programming languages]] |
||
[[Category:Aspect-oriented programming]] |
|||
[[Category:Functional languages]] |
|||
[[Category:Statically typed programming languages]] |
Latest revision as of 11:54, 15 November 2024
Paradigm | Multi-paradigm: aspect-oriented, event-driven, functional, generic, imperative, meta, object-oriented, reflective |
---|---|
Family | C# |
Designed by | Kamil Skalski, Michał Moskal, Prof. Leszek Pacholski, Paweł Olszta at Wrocław University |
Developer | JetBrains (formerly) RSDN |
First appeared | 2003 |
Stable release | 1.2.507.0[1]
/ 6 August 2016 |
Typing discipline | Inferred, nominal, static, strong |
Platform | CLI |
Filename extensions | .n |
Website | nemerle |
Major implementations | |
Nemerle | |
Influenced by | |
C#, Lisp, ML |
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, aspect-oriented, reflective 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 was focusing on developing Nitra, a framework to implement extant and new programming languages.[2][3][4] Both the Nemerle language and Nitra have seemingly been abandoned or discontinued by JetBrains; Nitra has not been updated by its original creators since 2017 and Nemerle is now maintained entirely by the Russian Software Development Network, independently from JetBrains, although no major updates have been released yet and development is progressing very slowly. Neither Nemerle, nor Nitra have been mentioned or referenced by JetBrains for years.
Nemerle is named after the Archmage Nemmerle, a character in the fantasy novel A Wizard of Earthsea by Ursula K. Le Guin.
Features
[edit]This section includes a list of references, related reading, or external links, but its sources remain unclear because it lacks inline citations. (September 2013) |
Nemerle's most notable feature is the ability to mix styles of programming that are object-oriented and functional. 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 object-oriented programming (OOP), in the style of C#, Java, and C++
- full support for functional programming, in the style of ML, OCaml, and Haskell, with these features:
- higher-order functions
- pattern matching
- algebraic types
- local functions
- tuples and anonymous types
- partial application of functions
The metaprogramming system allows for great compiler extensibility, embedding domain-specific languages, partial evaluation, and aspect-oriented programming, taking a high-level approach to lift as much of the burden as possible from programmers. The language combines all Common Language Infrastructure (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
[edit]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
[edit]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
[edit]def k = (1, "one"); // k : (int * string)
def (a, b) = k; // a = 1, b = "one"
Pattern matching
[edit]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
[edit]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
[edit]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
[edit]Nemerle's macro system allows for creating, analysing, and modifying program code during compiling. Macros can be used in the form of a method call or as a new language construct. Many constructs within the language are 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, 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
}
Braceless syntax
[edit]Similarly to the braceless syntax later added to Scala, Nemerle allows the programmer to optionally use a whitespace-sensitive syntax based on the off-side rule, similarly to Python.
The following curly-brace snippet:
using System.Console;
[Qux]
class FooBar {
public static Main(): void {
WriteLine("Hello")
}
static Foo (x: int): void {
if (x == 3) {
def y = x * 42;
Foo (x)
} else {
[x].Map (fun (x) {
x * 2
})
}
}
static Bar(): int {
def foo = 2 + 7 * 13;
foo
}
}
could be rewritten as:
using System.Console;
[Qux] \
class FooBar
public static Main(): void
WriteLine("Hello")
static Foo (x: int): void
if (x == 3)
def y = x * 42;
Foo (x)
else
[x].Map (fun (x) {
x * 2
})
static Bar(): int
def foo = 2 + 7 * 13
foo
Notably, it is not possible to break expressions or alternative clauses in matches over multiple lines without using a backslash \
:
// This will not compile ...
static Bar(): int
def foo = 2
+ 7
* 13
foo
match (s)
| "a"
| "aa" => 1
| "b"
| "bb" => 2
| _ => 0
// But this will:
static Bar(): int
def foo = 2 \
+ 7 \
* 13
foo
match (s)
| "a" \
| "aa" => 1
| "b" \
| "bb" => 2
| _ => 0
In order to activate this syntax, the user must add #pragma indent
to the top of the file or use the compiler option -i
.
IDE
[edit]Nemerle can be integrated into the integrated development environment (IDE) Visual Studio 2008. It also has a fully free IDE based on Visual Studio 2008 Shell[5] (like Visual Studio Express Editions) and SharpDevelop (link to plugin source code).
Nemerle can be also integrated into Visual Studio (up until 2017) using add-ins and extensions.[6]
Examples
[edit]Hello, World!
[edit]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
[edit]Macros allow generating boilerplate code with added static checks performed by the compiler. They reduce the amount of code that must be written by hand, make code generation safer, and allow programs to generate code with compiler checks, while keeping source code relatively small and readable.
String formatting
[edit]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
[edit]StructuralEquality, Memoize, json, and with are macros which generate code in compile time. Though some of them (StructuralEquality, Memoize) can look like C# attributes, during compiling, 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
[edit]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
[edit]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
[edit]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
[edit]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
[edit]- ^ Nemerle 1.2.507.0
- ^ "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". Retrieved 2013-09-05.
- ^ Nemerle Studio Microsoft Setup Installer can be installed after installing Visual Studio Shell 2008 Isolated
- ^ Visual Studio 2010 add-in
Further reading
[edit]- 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