-
Notifications
You must be signed in to change notification settings - Fork 89
Quick guide
This is a small guide to nearly all Nemerle features, specially for people coming from C#:
-
mutable a = 5;
: mutable variables can be changed later -
def b = 4;
: normal variables cannot be changed
-
def c : float = 4;
: a type annotation
-
def nil = [];
: the empty list is [] -
def numbers = [1, 2, 3];
: generate a list with those values -
def more_numbers = 4 :: numbers
; : :: adds a new item to the list
-
$[ (x, y) | x in list1, y in list2, x < y]
: get all pairs on the lists for which the condition is true. -
$[1, 3 .. 8]
: range from 1 to 8 step 2 (3-1) -
$[1 .. 5]
: range from 1 to 5 step 1 -
$[ (x, y) | x in [1 .. 3], y in [2, 4 .. 10] ]
: generate all pairs
-
Length, Head, Tail, Last, Nth
-
FirstN
: return first N elements of the list -
ChopFirstN
: return the list without the first N elements -
LastN
: return the last N elements -
Reverse
-
Remove
: removes an element -
Contains
-
Iter (f : 'a -> void)
: executes the function in all elements -
Map (f : 'a -> 'b)
: returns a new list['b], executing the function in all elements of the list['a] -
Group (f : 'a * 'a -> int)
: return a list of lists, grouping the elements whose function returns the same value -
FoldLeft, FoldRight
: returns a result of executing the function recursively on the list, with a first element, in normal or reverse order -
ForAll (f : 'a -> bool)
: returns true if all elements return true -
Exists (f : 'a -> bool)
: returns true if at least one application of the function in the elements returns true -
Find (pred : 'a -> bool)
: finds the first element whose predicate is true -
Filter (pred : 'a -> bool)
: returns a new list containing all elements whose predicate is true -
Sort (cmp : 'a * 'a -> int)
: sorts the list based on the method. The reason underlying the fact that the function returns an int is that CompareTo functions in .NET return an int -
RemoveDuplicates
-
ToArray
Iter
, Map
or Fold
, for example, Hashtable
(that extends Dictionary
) or LinkedList
.
-
def a = array(3);
: specifies the number of elements -
def b = array[1, 2, 3]
: specifies the elements
-
def t = (1, "one");
: a tuple is a set of values with no name to recognise them -
def fst = t[0];
: use 0-based index to get the items
This class contains three methods that work with pairs (tuples of two elements):
-
First
andSecond
retrieve the first or second element of the tuple, respectively -
Swap
exchanges both elements of the pair
-
when (condition) code
: execute code if condition is true -
unless (condition) code
: execute code if condition is false -
if (condition) code1 else code2
: execute code1 if condition is true, code2 if it is false
-
for (mutable i = 0; i < 10; i++) code
: for loop as of in C -
foreach (i in $[0..9]) code
like the above, using range -
foreach (i in $[9,8..0]) code
reverse order -
while (condition) code
: execute code while condition is true -
do code while (condition)
: the same as above, but checks the condition at the end of the code, so it is always run at least once -
foreach (x in list) code
: execute the code for every member x of the enumerable collection list -
foreach (x when x != null in list) code
: like the above but only for not null members -
repeat (10) code
: repeats the code the specified number of times
-
throw ArgumentException();
: throws a new exception of the desired type - Syntax for try-catch-finally handler resembles the one from C#, although catch handlers use a pattern matching-like syntax:
try {
code
}
catch {
| e is ArgumentNullException => ...
| e is OverflowException => ...
| e is MyException when e.Reason == Reason.Warn => ...
| _ => ...
}
finally {
// Finally code is always executed
// no matter an exception were thrown or not
}
- Create a variant with empty options and options with extra information
variant Volume {
| Max
| Min
| Other { v : int }
}
-
def v1 = Volume.Max ();
: an empty constructor is used for empty options -
def v2 = Volume.Other (5);
: the constructor for non-empty elements gets all fields as parameters, in the order they were written in code - You need to include
[XmlSerializable]
on top of the variant to make it serializable via XML
As in C#, are just a good face for ints:
enum Seasons {
| Spring
| Autumn
| Winter
| Summer
}
Value-types (structs) cannot be null (that's a platform requirement). However, sometimes you need nullable integers or booleans.
-
def t : int? = 3;
: declare a new nullable int with a value -
def t : int? = null;
: declare a new nullable int with null value -
when (t != null) {...}
: boolean expressions are overloaded to check for values on nullable types. This is the same as sayingwhen (t.HasValue) {...}
-
a = b ?? -1;
:a
gets the wrapped value ofb
if is isn't null. Otherwise, it gets the value after the two question marks -
a = b?.P;
: ReturnsP
ifb
is not null, or default(typeof(b.P)
) otherwise. Avoids NullReferenceException. The left side of the operator (b
) must be a reference type.
- Numbers:
match (value) {
| 1 => "one"
| 2 => "two"
| _ => "more"
}
- Strings:
match (value) {
| "one" => 1
| "two" => 2
| _ => 0
}
- Enums:
match (value) {
| Seasons.Spring
| Seasons.Summer => "hot"
| _ => "cold"
}
match (some_list) {
| [42, 42] => "two forty-two"
| [42, _] => "forty-two on first position of two-element list"
| [_, 42] => "forty-two on second position of two-element list"
| 42 :: _ => "forty-two on first position"
| _ :: 42 :: _ => "forty-two on second position"
| [] => "an empty list!"
| _ => "another list"
}
Binds the variable names:
def display (l) {
match (l) {
| head :: tail =>
Write ($ "$head, ");
display (tail)
| [] =>
WriteLine ("end")
}
}
match (tuple) {
| ( 42, _ ) => "42 on first position"
| ( _, 42 ) => "42 on second position"
| ( x, y ) => $"( $x, $y )"
}
Checks if the value is of given type, binding the new value with the new type
def check (o : object) {
match (o) {
| i is int => $"An int: $i"
| s is string => $"A string: $(s.ToUpper())"
| _ => "Object of another type"
}
}
Binds on field or properties
def check_class (c) {
match (c) {
| MyClass where (foo = 0) => true
| _ => false
}
}
where
clause is not needed
def check_class (c) {
match (c) {
| (foo = 0) => true
| _ => false
}
}
Binds a value matched with an identifier
variant Foo {
| A { x : int; mutable y : string; }
| B
}
match (some_foo ()) {
| A (3, _) as a =>
a.y = "three";
| _ => {}
}
Used to explicitly declare types where the compiler cannot infer it
def foo (l) {
| (s : string) :: _ => s [0]
| [] => '?'
}
Used to specify a default value in cases where we need to match both a small and a big structure with the same code.
def foo (_) {
| [x] with y = 3
| [x, y] => x * y
| _ => 42
}
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");
}
you must add a reference to Nemerle.Text to use this functionality (using Nemerle.Text)
- Works as in C#, used for enumerating sequences:
Range (from : int, to : int) : IEnumerable[int] {
for (mutable i = from; i <= to; i++)
yield i;
}
To use return
, break
and continue
we need to open the Nemerle.Imperative
namespace:
-
return x;
: cuts the execution of the function, method or property, stablishing x as the return value -
continue;
: on a loop, continues with the next iteration -
break;
: on a loop, cuts the execution of the loop and continues with the following code
def x =
foo: {
when (some_cond) foo (3); // if some_cond is true, the block will return
qux ();
42 // else it will return 42
}
- Functions can be declared inside methods, and type inference works for them:
public Greet (people : list[string]) : void {
def say_hello (s) {
System.Console.WriteLine ($"Hello $s");
}
foreach (person in people)
say_hello (person);
}
-
compute (f : int * int -> int, x : int, y : int) { ... }
: functions can be passes as parameters, whose types are divided by * and its return type is told after -> -
compute ( fun (x, y) { x + y }, 3, 4)
: anonymous functions can be created inline, just preceding them with fun and its list of parameters -
compute ( (x, y) => x + y, 3, 4)
: anonymous functions have multiple forms -
def addFive = compute (fun (x, y) { x + y }, _, 5)
: partial application, substitutes one or more parameters, then yielding another function with a smaller set of parameters -
def addFive = _ + 5;
: partial application substituting the parameter with _ -
def name = _.Name;
: you can also use this type of partial application to access members -
lambda x -> Console.WriteLine (x)
: a easier construct to create a function with just one parameter
-
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
-
print (value), sprint, fprint
: substitutes variable names with $ notation in the string and returns it to Console, string or TextReader, respectively -
printf (value), sprintf, fprintf
: as above, but with formatting -
scanf (format), sscanf, fscanf
: returns a string extracted from console, string or TextReader that keeps the specified format
-
def s = n :> int;
: cast may fail with an InvalidCastException -
def s = n : int;
: cast cannot fail, only for supertypes
-
namespace NS { ... }
: declares a new namespace -
using System;
: open the namespace, that is, makes all members inside it not to requiere full qualifying. It also opens namespace inside it (different with C#) -
using System.Console;
: open the type, making its methods visible -
using C = System.Console;
: create an alias to refer the type or namespace
-
class Example { ... }
: creates a class Example -
module Example { ... }
: creates a module Example, that is, a class with all members static
Defines a set of public methods an adhering class must implement
interface IExample {
Method() : void;
}
class Example : IExample {
public Method () : void { ... }
}
-
public
: everyone can access -
internal
: only classes in the current assembly (DLL or EXE) can access -
private
only current type can access -
protected
: access is limited to current type and its derived types -
protected internal
means protected or internal - access limited to derived types or types in the current assembly
-
static
: no instance is needed for accessing -
mutable
: if not set for field, they are read-only -
volatile
: only for fields, it means that the field has to be always read from the memory, and written instantly. Useful for multithreaded programs -
extern
: used on methods, along with DllImport attributes to call out to native code -
partial
: only on type definitions, it means that a given type definition is split across several files
- Take
this
as its name:
class Example {
mutable Name : string;
public this (name : string) {
Name = name;
}
}
-
def n = Example ("serras");
: nonew
keyword is used to create new objects
Executed once per type. No parameters.
class Example {
static public this() { ... }
}
: operator will be used by compiler to automatically convert from one value to another if it is needed, like passing objectRecord] macro]
Generates a constructor which assigns a value to every field:
[Record] class Point {
public x : int; public y : int;
}
class Point {
public x : int; public y : int;
public this (x : int, y : int) {
this.x = x; this.y = y
}
}
-
class Human : Mammal { ... }
: class Human inherits from Mammal, or implements Mammal interface
-
abstract
: the method contains no actual implementation, that must be provided in child classes -
override
: redefinition of a virtual or abstract method -
virtual
: the most derived method will always be called -
new
: allows name redefinition in nested or derived classes -
sealed
: no derivation or redefinition is possible in derived classes
-
method (x : int, y : int, z : bool = false) { ... }
: default parameters -
method (i : ref int) { ... }
: passes the parameter by reference, that is, changing the actual value -
method (i : out int) { ... }
: specifies an out parameter, used for returning values - Values passed as
ref
orout
parameters must be decorated with theref
orout
keyword -
Write (method (3, z = true, y = 1));
: parameter names can be used, after unnamed ones
public Property : string {
get { property }
set { property = value }
}
-
[Accessor (Sum)] mutable sum : int;
: generate a public property with name Sum, getting the value from the field sum, with just a getter -
[Accessor (Sum, flags=Internal)] mutable sum : int;
: change the accessibility -
[Accessor (Sum, flags=WantSetter)] mutable sum : int;
: generate both getter and setter -
[Accessor] mutable sum_of_sam : int;
: property name used, capitalized and underscores removed : SumOfSam
For setting individual bits of enumerations fields, making boolean propeties:
[System.Flags] enum States {
| Working = 0x0001
| Married = 0x0002
| Graduate = 0x0004
}
[FlagAccessor (Working, Married, Graduate, flags=WantSetter)]
mutable state : States;
class Table {
public Item [row : int, column : int] {
get { ... }
set { ... }
}
}
[Record]
class Vector {
[Accessor] x : double;
[Accessor] y : double;
[Accessor] z : double;
// + operator
public static @+ (v1 : Vector, v2 : Vector) : Vector {
Vector (v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z)
}
// implicit cast operator
public static @: (p : Point) : Vector {
Vector (p.X, p.Y, p.Z)
}
// explicit cast operator
public static @:> (p : double) : Vector {
Vector (p, 0.0, 0.0)
}
}
: operator will be used by compiler to automatically convert from one value to another if it is needed, like passing object to method expecting some different type. Cast :> must be explicitly written by user, like def x = A() :> B;
-
delegate Foo (_ : int, _ : string) : void;
: creates a new delegate type -
def f1 = Foo (method);
: creates a delegate instance containing a reference to a method or function -
def f2 = Foo ( fun (i, s) { ... } );
: creates a delegate containing an anonymous function -
event MyEvent : Foo;
: creates an event field of delegate type Foo -
Foo += method;
: adds a method to the delegate -
Foo -= method;
: remove a method from the delegate -
Foo (2, "two");
: invokes a delegate, that is, calls all the methods in it, in the order they were added, passing these parameters
- A generic type:
class Example[T] {
mutable item : T;
public foo [Z] () : void { }
}
- Generic functions, variants and methods use the same syntax
-
def x = Example[int].foo.[string]();
: for rare cases where generic parameter cannot be inferred
-
class Example['a] where 'a : IComparable['a] { ... }
: 'a must implement or inherit the class or interface stated -
class Example['a] where 'a : class {...}
: 'a must be a reference type -
class Example['a] where 'a : struct {...}
: 'a must be a value type -
class Example['a] where 'a : enum {...}
: 'a must be an enumeration type -
class Example['a] where 'a : new () {...}
: 'a must implement a parameterless constructor. That's the only way you can create instances of classes defined by type parameters
-
class Example[+T] { ... }
: makes the argument type covariant, that is, you can assign, to a variable of typeExample[T]
an instance ofExample[U]
if U subclasses T (for example, you could assign an instance ofExample[string]
to anExample[object]
variable). Covariant type parameters can only be used as return types. -
class Example[-T] { ... }
: makes the argument type contravariant, that is, you can assign, to a variable of typeExample[T]
an instance ofExample[U]
if T subclasses U (for example, you could assign an instance ofExample[object]
to anExample[string]
variable). Contravariant type parameters can only be used as argument types or in generic interfaces.
- You can declare an extension method by adding
this
to the first parameter:
namespace ExtensionExample {
class ExtensionClass {
public static PlusOne (this i : int) {
i + 1
}
}
}
- You need to open the namespace to use the extension method as member methods:
using ExtensionExample;
def n = 3;
def m = n.PlusOne (); // that will call the extension method```
== Design by contract ==
All types needed are included in the <code>Nemerle.Assertions</code> namespace. By default, if contract is violated a <code>Nemerle.AssertionException</code> is thrown. You can change it by means of <code>otherwise</code>
```nemerle
getfoo (i : int) : int
requires i >= 0 && i < 5 otherwise throw
System.ArgumentOutOfRangeException ()
{ ... }
- On a method:
class String
{
public Substring (startIdx : int) : string
requires startIdx >= 0 && startIdx <= this.Length
{ ... }
}
- On a parameter:
ConnectTrees (requires (!tree1.Cyclic ()) tree1 : Graph,
requires (!tree2.Cyclic ()) tree2 : Graph,
e : Edge) : Graph
{ ... }
public Clear () : void
ensures this.IsEmpty
{ ... }
- Assign class invariants:
class Vector [T]
invariant position >= 0 && position <= arr.Length
{ ... }
- Use
expose
to change the invariants
expose (this) {
x += 3;
y += 3;
}
-
def l = lazy (MethodWithBigCost ());
: declares a variable whose value will be retrieved only when needed -
method ([Lazy] x : int, y : int) { ... }
: the parameter will only be fetched in rare cases - The field
Next
will only be evaluated when requested, because or itsLazyValue
type:
class InfList {
public Val : int;
public Next : LazyValue [InfList];
public this (v : int) {
Val = v;
Next = lazy (InfList (v + 1));
}
}
Late expressions are executed dynamically at runtime, which makes it perfect for uses such as COM. No strict checks are done, so you must take care of calling the correct method on the correct instance and so on.
-
late (expr)
orlate expr
: executes a valid Nemerle expression with late binding. -
nolate (expr)
ornolate expr
: allows executing a expression as if it wasn't late in a late binding environment. -
late obj.Length
: theLength
property or field is retrieved at runtime, so you could use it over strings, lists, arrays... without worrying of the type. Of course, if the object does not contain aLength
member, an exception will be thrown. -
late o.Name.[1]
: calls the default indexer on o.Name. You must be aware that callingo.Name.Chars[1]
calls the indexer namedChars
ono.Name
.
-
type int = System.Int32;
: establishes an alias for the System.Int32 type. int can be used anywhere in code with the exact same meaning as System.Int32.
[Alias (F2, F3 ())]
public static F1 () : int { System.Random ().Next () }
F2
property and a F3
method with no arguments:
public F2 : int { get { System.Random.Next () } }
public F3 () : int { System.Random.Next () }
[Alias (Hd, Head2 (), Head3 (l))]
public static Head (l : list ['a]) : 'a {
match (l) { ... }
}
this
. Method arguments must match the ones from the method being aliased, but their order can be changed. The previous code generates:
public Hd : 'a { get { def l = this; match (l) { ... } } }
public Head2 () : int { def l = this; match (l) { ... } }
public static Head3 (l) : int { match (l) { ... } }
-
a = b;
: assignment. In Nemerle, this operator doesn't return a value, so multiple assignments are not allowed- Compound assignment is allowed:
a += b;
- Compound assignment is allowed:
-
+
: number addition, string concatenation -
-, *, /, %
: number substraction, multiplication, division and modulo -
a &lt;-&gt; b;
: swap, exchanges values of a and b -
++, --
: adds or substract 1 to the value -
+, -
-
==, !=
: equal, not equal -
x.Equals(y)
: compare any two objects. x and y may have different types. Types are allowed to provide their own override of theEquals
method, by default, it checks by reference in reference types and by value in value types (including enums) -
&gt;, &lt;, &gt;=, &lt;=
: greater than, less than, greater or equal to, less or equal to -
&&
: short-circuiting and -
||
: short-circuiting or -
!
: not
and, or, not
if you open the Nemerle.English
namespace
-
&, |, ^
: bit-level and, or and xor operations -
%&&, %||, %^^
: bit-level and, or and xor, returning true if the result is non-zero -
&gt;&gt;, &lt;&lt;
: right and left bitwise shift
-
unchecked { ... }
: any number operation that goes beyond the limits of the type will silently go into an overflow -
checked { ... }
: operations overflowing will throw aOverflowException
-
using (resource) { ... }
: the resource must implement the IDisposable interface. This block assures the resource is correctly disposed even though an exception is thrown -
lock (object) { ... }
: for multithreaded application. Assures that no other code executes this block if the block object is being used
All macros are inside the Nemerle.Logging
namespace:
-
[assembly: LogFunction (DoLog)]
: specifies a logging function -
[assembly: LogFunction (DEBUG => log4net_category.Debug, TRACE => log4net_category.Info)]
: specifies different logging functions for different compilation flags -
log (VERB, "example", 2)
: calls the logging function if the compilation flag is set, with those parameters -
whenlogging (VERB) { code }
: executes the code only if the compilation flag is set -
[assembly: LogFlag (VERB, true)]
: sets the compilation flag for VERB to true -
[assembly: LogCondition (EnableLogging), LogFlag (DEBUG, true)]
: add a condition that will be cheked each time the log function is called -
[assembly: LogFormat (PrependFlag)]
: prepend logging flag to each message
-
assert (condition, "message");
: if condition is false, a AssertionException will be thrown, with the actual line and column number in the code file
-
[assembly: ProfSetup]
: add initial setup for profiling -
[Profile] foo () : int { ...}
: tell the profile to include this method -
[ProfDump] Dump () : void { }
: each call to this method will show the results of the profiling
-
[ConfigureConnection (connectionString, name)]
: applied to a class, tells the compiler about the connections used later in other SQL macros -
ExecuteNonQuery ("INSERT INTO employee VALUES ('John', 'Boo')", connection);
: executes the query returning no results, via the specified connection -
def count = ExecuteScalar ("SELECT COUNT FROM employee WHERE firstname = $myparm", connection);
: retrieves just one result, using the specified connection. See you can use the $ notation to substite variables - Execute a code for every returned result, binding the column names to variables. Beware that the code is just another parameter, so you need to end parenthesis after them
ExecuteReaderLoop ("SELECT * FROM employee WHERE firstname = $myparm",
dbcon,
{
Nemerle.IO.printf ("Name: %s %s\n", firstname, lastname)
});
All this macros are in Nemerle.Concurrency
namespace
-
async { ... }
: You can execute any block of code asynchronously: - Additionally, you can create a method that will always execute asynchronously:
async Read (s : string) { ... }
Chords are sets of methods that only return a value when some exact amount of them are called in some order. This example states very well both the syntax and uses of chords:
class Buffer [T]
{
[ChordMember]
public Put (msg : T) : void;
public Get () : T
chord {
| Put => msg
}
}
All in Nemerle.Collections
namespace:
-
ICollection['a]
: extends .NETICollection
by adding contract for mapping, folding, itering... -
Hashtable['a, 'b]
: extendsSystem.Collections.Generic.Dictionary[K, V]
by addingFold
,Map
andIter
methods.Hastable
saves items with an unique key -
Heap
: saves a list of objects, allowing only to extract the first removing (ExtractFirst
) or not removing (Top
) it. Like usual, allowsMap
,Iter
andFold
operations. -
LinkedList['a]
: extends .NET genericLinkedList
, adding some useful, list-like methods -
Queue['a]
: like always, extends .NETQueue['a]
by adding the useful list-like methods likeIter
,Fold
,Map
... Queues are data structures which only allow to add or remove items at the end or the start of them -
Set['a]
: an implementation of mathematical sets. It allows all normal operations on list plus:-
Sum
: adds two sets yielding only one replica of each duplicated element -
Substract
: returns all elements of the first set that are not in the second one -
Intersect
: return the elements that appear on both sets -
Xor
: return the elements that appear in one of the sets, but not in both
-
-
Stack['a]
: extends .NETStack
, a class which allows to add or remove items only on the top of them -
Tree
contains an implentation of Red-Black trees, an useful structure -
RList
(Random Access List) is a purely functional data structure
This methods live in Nemerle.Utility
namespace, in NArray
and NString
classes, but can be used in arrays and string in code in a normal way. The methods adds functionality a la list for these two types.
Contains helper functions for handling an input stream: ReadIntDigits, ReadRealDigits, ReadString, ReadChar, ConsumeWhiteSpace and CheckInput
.
The type option['a]
allows to save values that can be null. option.None
tells that it has no value. option.Some (value)
saves a value. You can also use the nullable types (discussed above), but they are limited to valuetypes.