This is a quick guide covering nearly all of Nemerle's features. It should be especially useful to anyone who is already familiar with C# or a similar language:

Table of Contents

Variables

  • mutable a = 5;: mutable variables can be changed later
  • def b = 4;: normal variables cannot be changed

The type of the above variables is inferred by the compiler. This is the norm, rather than the exception.

Variables can be manually assigned types as follows: def c : float = 4;

  • def f' = f.getDerivative();: variable and type names using and starting with " ' " are valid in Nemerle

Operators

  • a = b;: assignment. This operator doesn't return a value, so a = b = c is not allowed

    • Compound assignment is allowed: a += b;
  • +: addition and string/list concatenation
  • -, *, /, %: subtraction/multiplication/division/modulo
  • a <-> b;: swap (exchanges the values of a and b)
  • ++, --: adds/subtracts 1 to/from a value

Logical Operators

  • ==, !=: equal/not equal
  • x.Equals(y): compares any two objects. Equals() checks by reference for reference types and by value for value types (including enums) by default. Types are allowed to provide their own override of the Equals method, and x and y may have different types.
  • >, <;, >=, <=: greater than/less than/greater than or equal to/less than or equal to
  • &&: logical AND
  • ||: logical OR
  • !: not

You can also use and/or/not by opening the Nemerle.English namespace

Bit Operators

  • &, |, ^: bit-level and/or/xor operations
  • %&&, %||, %^^: bit-level and/or/xor, returning true if the result is non-zero
  • >>, <<: right/left bit-shifting

Type Casts/Conversions

The implicit cast operator is used if a cast cannot fail (ie when casting to a supertype):

def x : int = 12; //Declaring a variable.
def y : long = x : long; //Casting it to something else.

The explicit cast operator is used if a cast may fail:

def x : int = 12; //Declaring a variable.
def y : char = x :> char; //Casting it to something else.

If an implicit cast is possible, the compiler will infer it and the use of the operator is not required.

$-Notation

$-Notation is the simplest way of inserting variables' values into strings in Nemerle.

  • def s = $"The number is $i";: replaces $i with the string value of i
  • def s = $"$x + $y = $(x+y)";: replaces $(...) with the string value of whatever is inside the parentheses. Useful for accessing members, performing calculations, and placing text immediately next to variables

Functions

Functions in Nemerle are declared either locally or as methods and return the value of their final statement. Regardless of how they are declared, they will generally look as follows:

add(a : int, b : int) : int {
a + b; //This function returns a + b.
}

Methods

When declared as a method, a function's return and parameter types must be explicitly stated:

class Greeter{
public Greet (name : string) : void { //Note the explicit types.
System.Console.Write($"Hello $(name)!");
}
}

Local Functions

Functions can be declared locally within methods and other functions. When declared locally, parameter and return types can be inferred.

class Greeter{
public GreetTwice (name : string) : void { //A function declared as a method. Types must be explicitly stated.
def sayHello(name) { //The types of this function are inferred
System.Console.Write($"Hello $(name)!");
} sayHello(name);
sayHello(name);
}
}

Function Types

Functions have types in Nemerle. Function types take the form of:

parameterTypes -> returnType

The type of the function

doSomething(i : int, c : char, s : string) : long {
//Or don't do something.
}

is:

int*char*string -> long

Note that parameter types use the same notation as tuple types.

Functions as Parameters

Functions may use other functions as parameters:

def compute(f : int*int -> int, x : int, y : int){
f(x,y)
} def add(a, b){a + b}
def mul(a, b){a * b} compute(add,2,3); //Returns 5
compute(mul,2,3); // Returns 6

Anonymous Functions and Partial Applications

All anonymous functions can be created using two different syntaxes:

  • compute ( fun (x, y) { x + y }, 3, 4): The fun keyword.
  • compute ( (x, y) => x + y, 3, 4): This alternate form.

The following syntax can be used for single variable functions:

def addFive = _ + 5;
addFive(10); // returns 15

It can also be used to access members:

def getName = _.name;
getName(hasName); //returns hasName.name

A partial application replaces one or more parameters of a function with some known value and yields another function with fewer parameters:

def addFive = compute (fun (x, y) { x + y }, _, 5);
addFive(6); // returns 11

Parameter Modifiers

Methods (but not local functions) may be passed arguments by reference using the 'ref' and 'out' modifiers.

Values passed using 'ref' must be initialized first:

public module Mod{
public static Main(): void{
mutable a = 3141, b = 2718;
Mod.swap(ref a, ref b);
System.Console.WriteLine($"a == $a and b == $b"); //Prints "a == 2718 and b == 3141"
} public swap(a : ref int, b : ref int) : void{
def temp = a;
a = b;
b = temp;
}
}

Values passed using 'out' do not need to be initialized first:

public module Mod{
public static Main(): void{
mutable a, b;
Mod.init(out a, out b);
System.Console.WriteLine($"a == $a and b == $b"); //Prints "a == 2718 and b == 3141"
} public init(a : out int, b : out int) : void{
a = 2718;
b = 3141;
}
}

Default Parameter Values/Passing Arguments By Name

Parameters can be given default values, and arguments may be passed to functions using parameters' names:

def add(a = 4,b = 5){
a + b;
} add() //returns 9
add(10) //returns 15
add(10,10) //returns 20
add(b = 20) //returns 24
add(b = 20, a = 30) //returns 50

Classes and Modules

  • class Example { ... }: creates a class Example
  • module Example { ... }: creates a module Example. A module is a class in which all members are static.

Access Modifiers

  • public: can be accessed from anywhere.
  • private: can only be accessed by the class itself.
  • protected: can be accessed by the class itself and child classes.
  • internal: public within the assembly (DLL or EXE) where it was defined, and inaccessible elsewhere.
  • protected internal: public within the assembly (DLL or EXE) where it was defined, and protected elsewhere.

Other Modifiers

For Methods and Fields

  • static: Only a single instance exists. This instance is accessed statically:ClassName.StaticMember()

Fields Only:

  • mutable: Makes a field modifiable. Fields are immutable (read-only) by default.
  • volatile: Specifies that the field must always be read-from/written-to memory. Useful for multithreaded programs.

Methods Only:

  • extern: Used with DllImportAttribute to call native code.

Other:

  • partial: Only used with type definitions. Indicates a given type definition is split across several files.

Constructors

Constructors look like methods but use this for their name:

class Example {
mutable Name : string;
public this (name : string) {
Name = name;
}
}
  • def n = Example ("serras");: creates a new instance. No 'new' keyword is required.

Static Constructors

Executed once per type. No parameters.

class Example {
static public this() { ... }
}

[Record]

Generates a constructor which assigns a value to every field:

[Record] class Point {
public x : int; public y : int;
}

is the same as:

class Point {
public x : int; public y : int;
public this (x : int, y : int) {
this.x = x; this.y = y
}
}

Inheritance

  • class Human : Mammal { ... }: class Human inherits from Mammal or implements the interface Mammal

Inheritance Modifiers

  • abstract: The method contains no actual implementation, and must be overridden by a child class.
  • virtual: The method may be overridden by child classes.
  • override: Indicates that the method redefines an abstract or virtual method.
  • sealed: Used in conjunction with override. Indicates that no further derivation or redefinition is possible.
  • new: Allows name redefinition in nested or derived classes.

Interfaces

Defines a set of public methods an adhering class must implement

interface IExample {
Method() : void;
} class Example : IExample {
public Method () : void { ... }
}

Properties

Properties are syntactic sugar for using setter/getter methods.

class Example{
private mutable minutes: int; public Hours : int {
get { minutes/60 }
set { minutes = 60*value } //a setter can be excluded to create a read-only variable
} public Minutes: int {
get { minutes }
set { minutes = value }
}
}

Property Accessors

  • [Accessor (Sum)] mutable sum : int;: generates a public property named Sum, getting the value from the field sum. Only a getter is generated.
  • [Accessor (Sum, flags=Internal)] mutable sum : int;: changes the accessibility
  • [Accessor (Sum, flags=WantSetter)] mutable sum : int;: generates both a getter and setter
  • [Accessor] mutable sum_of_sam : int;: generates the property SumOfSam

more...

Operator Overloading

Operator overloads are defined using @:

[Record] //Creates a constructor which sets all fields in the order defined.
class Vector {
[Accessor] x : double; //Creates a property X
[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)
} // Overrides the implicit cast operator to allow the conversion of a Point to a Vector.
public static @: (p : Point) : Vector {
Vector (p.X, p.Y, p.Z)
} // Overrides the explicit cast operator to allow the conversion of a double to a Vector.
public static @:> (p : double) : Vector {
Vector (p, 0.0, 0.0)
}
}

Implicit casts (the : operator) will be automatically used by the compiler to convert from one type to another when assigning values or passing arguments to functions. Explicit casts (the :> operator) must be manually stated.

Hence:

needsVector(somePoint); //A Point can be passed to a function which needs a Vector without writing out a cast.
needsVector(someDouble :> Vector); //A double must be explicitly converted

Indexers

Indexers allow access to an internal storage array within a class:

class Table [T]{
private storage : array[array[T]]; this(width : int, height : int){
//initialize storage
} public Item[row : int, column : int] : T {
get { storage[row][column]}
set { storage[row][column] = value;}
}
} def someTable = Table(11,11);
t[3,1] = 4159265;

Design By Contract

With Methods

Methods may use design by contract to check arguments and values before or after running. The namespace Nemerle.Assertions must be imported to do this.

using Nemerle.Assertions;

public class Example{
public DoSomething(mutable i : int) : int
requires 0 <= i && i <= 5 otherwise throw System.ArgumentException() //Checked before running.
ensures CleanUp() otherwise throw System.Exception("Clean Up failed.") //Checked after running.
{...}
}

If otherwise is not included and a contract is violated, then a Nemerle.AssertionExceptionwill be thrown by default.

Parameters may also be checked individually:

ConnectTrees (requires (!tree1.Cyclic ()) tree1 : Graph,
requires (!tree2.Cyclic ()) tree2 : Graph,
e : Edge) : Graph
{ ... }

Using Invariants

An invariant is a statement/function which should always evaluate to true. Classes declare invariants as follows:

using Nemerle.Assertions;

class Example
invariant IntegrityCheck() //A public function or one which uses expose can never be used here.
{
mutable x : int;
mutable y : int; private IntegrityCheck() : bool{
if(x>0)
x <= y && y <= 99
else
x != y
}
}

Invariants will be evaluated when public functions return and whenever expose is used:

expose (this) {
x += 3;
y += 3;
}//Invariants will be checked at the end of this block of code.

An assertion exception is raised if an invariant returns false.

more...

Namespaces

Namespaces are objects which may hold classes, modules, and other namespaces.

  • namespace SomeSpace { ... }: declares a new namespace
  • using SomeSpace;: opens the namespace (All objects in SomeSpace are now in scope)
  • using System.Console;: opens the type, making its static methods visible
  • using C = System.Console;: creates an alias referring to a type/namespace

Extension Methods

Extension methods are syntactic sugar for using a method from a module in a namespace on an object: MathSpace.Functions.Root(someInt) could be shortened to someInt.Root()for example.

To create extension methods, create a module inside of a namespace, and then add public methods whose first parameter is named 'this':

namespace ExtensionSpace {
module Extensions {
public PlusOne (this i : int) {
i + 1
}
public PlusOne (this i : string) {
i + "1"
}
}
}

To use extension methods, simply import the namespace where they were defined:

using ExtensionSpace;

def a = 3;
def b = "string";
WriteLine(a.PlusOne());
WriteLine(b.PlusOne());

A class's public static members could also be used to create extension methods, but creating a separate module for them is clearer.

more...

Generics

An example of a generic class and methods:

public class Example[T] {
public mutable item : T;
public foo [Z] (val : Z) : Z {
val;
}
public bar [C] () : void {}
}

Generic types can be inferred:

def a = Example(); //The class from above.
a.item = "Using Nemerle prevents carpal tunnel syndrome!";
System.Console.WriteLine(a.item);
  • Generic functions, variants, and methods all use the same syntax.
  • def x = Example[int].bar.[string]();: explicitly sets types. For the rare cases in which generic parameters cannot be inferred

Generic Type Constraints

  • class Example[T] where T : IComparable[T] { ... }: T must implement or inherit the class or interface stated
  • class Example[T] where T : class {...}: T must be a reference type
  • class Example[T] where T : struct {...}: T must be a value type
  • class Example[T] where T : enum {...}: T must be an enumeration type
  • class Example[T] where T : new () {...}: T must implement a parameterless constructor. This is the only way to create a new T within Example.

Covariance and Contravariance

  • class Example[+T] { ... }: makes the argument type covariant. Covariant type parameters can only be used as return types.
  • class Example[-T] { ... }: makes the argument type contravariant. Contravariant type parameters can only be used as argument types or in generic interfaces.

Covariance Defined: If Child extends Parent, an instance of Example[Child] could be assigned to a variable of type Example[Parent]. An instance of Example[string] could be assigned to an Example[object] variable.

Contravariance Defined: If Child extends Parent, an instance of Example[Parent] could be assigned to a variable of type Example[Child]. An instance of Example[object] could be assigned to an Example[string] variable.

Reflection

The 'is' Keyword

Runtime type-checking can be performed using is:

def someObject = getSomeObject();
when(someObject is string){
(someObject :> string).ToUpper();
}

The above can be done more efficiently with pattern matching.

Standard Types

Lists

  • def nil = [];: an empty list
  • def numbers = [1, 2, 3];: creates a list with the values between the brackets
  • def more_numbers = 4 :: numbers; : :: adds a new item to the list
  • def list3 = list1 + list2; : :: concatenates two lists

List Comprehensions

  • $[ (x, y) | x in list1, y in list2, x < y]: gets all pairs on the lists for which the condition is true.
  • $[1 .. 5]: integers 1 through 5 stepping by 1
  • $[1, 3 .. 8]: integers 1 through 8 stepping by 2 (3-1 = 2)
  • $[ (x, y) | x in [1 .. 3], y in [2, 4 .. 10] ]: generates all pairs

more...

Useful Properties on Lists

  • Length : int: the length of the list
  • Head : T: the first element in the list
  • Last : T: the last element in the list
  • Tail : list[T]: a new list starting at the old list's second element

Useful Methods on Lists

  • FirstN(int : n) : list[t]: returns the first N elements of the list
  • ChopFirstN(int : n) : list[t]: returns the list without the first N elements
  • LastN(int : n) : list[t]: returns the last N elements of the list
  • Reverse() : list[T]: returns the reversed list
  • Remove(item : T) : list[T]: returns the list with all instances of item removed
  • Contains(item : T) : bool returns true/false if the list does/doesn't contain item
  • Iter (f : T -> void) : void: calls the given function using each element in the list as an argument
  • Map (f : T -> T') : list[T']: executes f using each element in the list[T] and returns the results as a new list[T']
  • Sort (cmp : T * T -> int): returns a new sorted list. Equality is determined by f, a function which compares two Ts and returns 1, 0, or -1 if the first T is greater than, equal to, or less than the second.
  • Group (f : T * T -> int) : list[list[T]]: Returns a list[list[T]] where each sub-list contains all elements which are considered equal. Equality is determined as in Sort()
  • FoldLeft(acc : T', f : T*T' -> T') : T': returns the result of executing frecursively on the list. more details
  • FoldRight(acc : T', f : T*T' -> T') : T': like FoldLeft(), but works through the list backwards.
  • ForAll (f : T -> bool) : bool: returns true if f returns true for all items in the list
  • Exists (f : T -> bool) : bool: returns true if f returns true for any item in the list
  • Find (pred : T -> bool) : Option[T]: returns, as an option, the first element predreturns true with
  • Filter (pred : T -> bool) : list[T]: returns a new list containing all elementspred returns true with
  • RemoveDuplicates() : void: removes duplicate elements
  • ToArray() : array[T]: returns the list as an array

Most of the BCL collection types have extended counterparts in the Nemerle library which contain many of the above methods. Nemerle.Collections.Hashtable extendsSystem.Collections.Generic.Dictionary for example.

Arrays

  • def a = array(3);: specifies the number of elements
  • def b = array(2, 3): specifies the number of elements in a multi-dimensional array
  • def c = array[1, 2, 3]: initializes with the specified elements
  • def d = array.[2] [ [1, 2, 3], [4, 5, 6] ]: initializes a multidimensional array with the specified elements

You can also specify array type:

def a = array(3) : array[byte];
def b = array[1 : byte, 2, 3];
mutable c : array[byte];

Tuples

  • def t = (1, "one", 'c');: a tuple is a set of values surrounded by parentheses
  • int*string*char: is the type of the above tuple
  • def fst = t[0];: tuples use a 0-based index to retrieve items

Nemerle.Utility.Pair

This class contains three methods that work with pairs (tuples of two elements):

  • First and Second retrieve the first or second element of the tuple, respectively
  • Swap exchanges both elements of the pair

Variants

  • The following creates a variant with two empty options and one option 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 uses all fields as arguments (in the order they were written)
  • You need to include [XmlSerializable] on top of a variant to make it serializable via XML

Enums

As in C#, enums are just syntactic sugar for a list of ints:

enum Seasons {
| Spring
| Autumn
| Winter
| Summer
}

FlagAccessor

The FlagAccessor macro automatically creates boolean properties from an internal enumeration:

class Person{
[System.Flags] enum States {
| Working = 0x0001
| Married = 0x0002
| Graduate = 0x0004
} [FlagAccessor (Working, Married, Graduate, flags=WantSetter)] //Will be read-only without flags=WantSetter
mutable state : States; //Value stored here.
} def casey = Person()
casey.Working = true;
casey.Married = false;

Nullable Primitives and Options

Nullable Primitives

Primitives cannot be null (as a platform requirement). However, sometimes nullable integers or booleans are needed.

  • def t : int? = 3;: declares a new nullable int whose value is 3
  • def t : int? = null;: declares a new nullable int whose value is null
  • when (t != null) {...}: is the same as when (t.HasValue) {...}
  • a = b ?? -1;a is set to the wrapped value of b if b isn't null. Otherwise, a is set to the value after the two question marks
  • a = b?.P;: Returns P if b is not null. Otherwise returns the default value of P)'s type. Avoids a NullReferenceException. b must be a reference type.

Options

Options are variants defined as follows:

public variant option[T]{ //A simplified version.
| None //has no value saved
| Some { val : T; } //Has some saved value 'val'
}
  • option.Value is a property used to access Some.val. It will throw an exception if the option's type is None.

Options are useful when a function needs to return a value which signifies "No Result", but returning null doesn't make sense. For example:

def li = ["list","of","strings","with","no","null","values"];
def li2 = ["list","with",null];
li.Find(_ == null) //returns None // _ == null is the same as fun(x){x == null}
li2.Find(_ == null).Value //returns null

Control Flow

If-Statements And The Like

Nemerle if-statements are slightly different from (clearer than) most languages. All if statements must be followed by an else statement. To replace solitary if statements, the 'when' and 'unless' constructs have been added.

  • when (condition) code: if condition is true, then execute code
  • unless (condition) code: if condition is false, then execute code
  • if (condition) code1 else code2: if condition is true, then execute code1. Otherwise, execute code2

Loops

  • 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
  • for (mutable i = 0; i < 10; i++) code: A standard C-style for-loop.
  • foreach (i in $[0..9]) code like the above, using a range
  • foreach (i in $[9,8..0]) code reverse order
  • foreach (x in list) code: execute the code for every member x of the enumerable collection list
  • foreach (x in list with index) code: like the above with available collection index
  • foreach (x when x != null in list) code: like the above but only for members which aren't null
  • repeat (10) code: repeats the code the specified number of times

Pattern Matching

Pattern matching checks if a variable or object matches a given pattern. If a match is found, then a specific bit of code is executed.

match(object)
| pattern1 => doSomething
| pattern2 when(someCondition) => doSomethingElse //when statements may optionally be used with a pattern
| pattern3
| pattern4 => doAnotherThing //Matching either pattern3 or pattern4 will execute this line.
| _ => doSomeOtherThing //Underscore represents a "wildcard". All variables will always match it.

Patterns are matched against from top to bottom and only one pattern can be matched.

Matching By Object Value (Simple Equality)

Pattern matching can most simply be used to check for equality. This functions much like a nicer looking switch statement:

  • Numbers:
match (value) {
| 1 => WriteLine("one");
| 2 => WriteLine("two");
| _ => WriteLine("more");
}
  • Strings:
match (value) {
| "one" => WriteLine(1);
| "two" => WriteLine(2);
| _ => WriteLine(0);
}
  • Enums:
match (value) {
| Seasons.Spring
| Seasons.Summer => WriteLine("hot");
| _ => WriteLine("cold");
}

Matching By Type

An object can also be matched against Types:

def check (o : object) {
match (o) {
| int => WriteLine("o is an int")
| string => WriteLine("o is a string");
| _ => WriteLine("o isn't an int or a string");
}
}

Matching Using Object Members

More advanced pattern matching can compare object members:

def killWhenFlanders (someone) {
match (someone) {
| Person where(name = "Flanders") => kill(someone)
| _ => () //Do nothing.
}
}

If the type is known to the compiler (most of the time), the class name and where clause aren't needed

def killWhenFlanders (someone) {
match (someone) {
| (name = "Flanders") => kill(someone)
| _ => () //Do nothing.
}
}
With List Members

Lists can be matched against patterns resembling:

match (someList) {
| [42, 42] => WriteLine("This list has two elements which are both 42.")
| [42, _] => WriteLine("This list has two elements and the first is 42.")
| 42 :: _ => WriteLine("The first element in this list is 42.")
| _ :: 42 :: _ => WriteLine("The second element in this list is 42.")
| [] => WriteLine("The list is empty!")
| _ => WriteLine("The list doesn't fit any of these patterns")
}
With Tuple Members

Tuples can be matched against patterns like the following:

match (tuple) {
| ( 42, _ ) => "This tuple has 42 in the first position."
| ( _, 42 ) => "This tuple has 42 in the second position."
}
''' ===== With Variants =====
```nemerle
variant Water{
| Liquid { depth : int; }
| Gas { density : float }
| Solid { pieces : int; volume : float }
} match (someWater) {
| Liquid (1) => WriteLine("The water has a depth of 1.")
| Solid (4, _) => WriteLine("There are four pieces of ice.")
| Gas => WriteLine("Steam!")
}

Binding Variables During Pattern Matching

Objects may be bound to variables during pattern matching. This is especially useful when matching functions.

Binding With 'as'

The as keyword binds the object being matched to a new variable if it matches the adjacent pattern:

match (getPerson()) {
| (name = "Flanders") as ned => ned.die()
| _ as somePerson => WriteLine($"Hello, $(somePerson.name)!")
}
Binding With 'is'

The is keyword binds the object being matched to a new variable based on its type:

def check (o : object) {
match (o) {
| i is int => $"An int: $i"
| s is string => $"A string: $(s.ToUpper())"
| _ => "Object of another type"
}
}
Binding Members

Members of a some objects may also be bound to variables:

match (list) {
| head :: tail => Write ($ "Head: $head, Tail: $tail")
| [] => WriteLine ("empty")
}
Binding Members Using 'with'

with is used to specify a default value for a member in cases where we need to match similarly structured objects using the same code.

def getArea(_) {
| [x] with y = 0
| [x, y] => x * y
| _ => 0
}
Binding Members Using Explicit Types

If for some reason the compiler cannot infer the type of a member, it can be explicitly stated:

def foo (l) {
| (s : string) :: _ => s [0]
| [] => '?'
}

Matching Regular Expressions

http://en.wikipedia.org/wiki/Regular_expression

using Nemerle.Text// Nemerle.Text is required to use this functionality

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");
}

Exceptions

  • throw ArgumentException();: throws a new exception of the desired type

Try/Catch/Finally

  • Nemerle's try-catch-finally syntax resembles that of C#. The major difference is that catch handlers use Nemerle's pattern matching syntax:
try {
code
}
catch {
| e is ArgumentNullException => ...
| e is OverflowException => ...
| e is MyException when e.Reason == Reason.Warn => ...
| _ => ...
}
finally {
// Finally code is always executed;
// whether an exception was thrown or not.
}

Assertions

  • assert (condition, "message");: if condition is false, an AssertionException will be thrown

Imperative Programming and Blocks

To use returnbreak and continue the Nemerle.Imperative namespace must be used:

  • return x;: stops the execution of a function/method/property and returns x
  • break;: stops the execution of a loop and moves on to the next bit of code
  • continue;: skips to the next iteration of a loop

Alternatively, "block" constructs may be used. A block is a set of instructions preceded with an identifier and a colon. The result of a block is either the last value computed or some value returned using the name of the block:

def x =
foo: {
when (some_cond) foo(3); // if some_cond is true, the block will return 3
qux ();
42 // else it will return 42
}

more...

The Nemerle Standard Library

Collection Classes

The Nemerle Collection classes/interfaces are all contained in the Nemerle.Collectionsnamespace.

Many of these classes extend items from the .NET Collections library with useful methods like IterFold, and Map:

  • ICollection[T]: extends System.Collections.ICollection[T]
  • Hashtable[K, V]: extends System.Collections.Generic.Dictionary[K, V]
  • Stack[T]: extends System.Collections.Stack
  • LinkedList[T]: extends System.Collections.GenericLinkedList[T]
  • Queue[T]: extends System.Collections.Queue[T]

Others provide additional functionality:

  • Tree an implentation of the Red-Black tree data structure
  • RList a Random Access List (a purely functional data structure)
  • Heap: a heap data structure. Only the top of the heap can be accessed.
  • Set[T]: an implementation of mathematical sets. It has all of list's operations as well as:
    • Sum: adds two sets yielding only one replica of each duplicated element
    • Subtract: 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

Array and String Extensions

Using the Nemerle.Utility namespace will allow the use of extension methods in theNemerle.Utility.NArray and Nemerle.Utility.NString classes. The methods add list-like functionality to arrays and strings.

Nemerle.IO

The following functions are contained in the Nemerle.IO namespace.

Print Functions

  • print(str), sprint(str), fprint(str): use $-notation to substitute variable names with their values before printing to the Console, a string, or a TextReader (respectively)
  • printf (value), sprintf, fprintf: as above, but with C-Style formatting instead of $-notation
  • scanf(format), sscanf(format), fscanf(format): returns a string extracted from the console, a string, or a TextReader with the specified format

Input Stream Functions

The Nemerle.IO namespace contains useful functions for handling an input stream:ReadIntDigits, ReadRealDigits, ReadString, ReadChar, ConsumeWhiteSpace, and CheckInput.

Other Constructs/Macros

Lazy Evaluation

  • def l = lazy( MethodWithBigCost() );: declares a variable whose value will only be assigned if it is used
  • someFunction([Lazy] x : int, y : int) { ... }: if passed a lazy argument, the function will only evaluate it if it is used

The field Next will only be evaluated when requested, because of its LazyValue type:

class InfiniteList {
public Val : int;
public Next : LazyValue [InfiniteList]; public this (v : int) {
Val = v;
Next = lazy(InfiniteList(v + 1));
}
}

more...

Late Binding

Late expressions are executed dynamically at runtime (which makes them perfect for things like COM). No strict type-checks are done, so be wary.

  • late(expr) or late expr: executes a valid Nemerle expression with late binding.
  • nolate (expr) or nolate expr: allows executing a expression as if it wasn't late in a late binding environment.
  • late obj.Length: the Length property or field is retrieved at runtime and can be used with strings, lists, arrays, etc without worrying about their type. If the object does not contain a Length member, an exception will be thrown during runtime.
  • late o.Name.[1]: calls the default indexer on o.Name. You should be aware that calling o.Name.Chars[1] calls the indexer named Chars on o.Name.

more...

Aliases

Type Alias

  • 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 Macro

The alias macro will transform

[Alias (F2, F3 ())]
public static F () : int { System.Random ().Next () }

into

public static F () : int { System.Random ().Next () }
public static F2 : int { get { System.Random.Next () } }
public static F3 () : int { System.Random.Next () }

Method arguments used in the macro must match those in the method being aliased, though their order can be changed. Arguments not specified will pass this:

[Alias ( Add(b) )]
public static Add (a : MyClass, b : MyClass) : MyClass {
//return a new MyClass using the values 'a' and 'b'.
} [Alias ( Root )]
public static Root (a : MyClass) : MyClass {
//return a new MyClass with the square root value of 'a'
}

Goes to:

public static Add (a : MyClass, b : MyClass) : MyClass {
//return a new MyClass using the values 'a' and 'b'.
}
public Add(b : MyClass) : MyClass{
def a = this;
//return a new MyClass using the values 'a' and 'b'.
} public static Root (a : MyClass) : MyClass {
//return a new MyClass with the square root value of 'a'
}
public Root : MyClass {
get{
def a = this; //return a new MyClass with the square root value of 'a'
}
}

Yield

  • Works as in C#, used for enumerating sequences:
Range (from : int, to : int) : IEnumerable[int] {
for (mutable i = from; i <= to; i++)
yield i;
}

Delegates and Events

  • delegate Foo(_ : int, _ : string) : void;: creates a new delegate type
  • def f1 = Foo(f);: creates a delegate containing the method/function f
  • 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;: removes a method from the delegate
  • Foo(2, "two");: invokes a delegate (calls all the methods in it, in the order they were added) with the given arguments

Concurrency

Lock

  • lock (object) { ... }: Synchronizes access to the block of code for object.object is usually this.

Concurrency Macros

The following macros are contained in the Nemerle.Concurrency namespace:

  • async { ... }: executes a block of code asynchronously
  • async Read (s : string) { ... } creates a method that will always execute asynchronously
Chords

A "chord" is a method which will block (halt the execution of its thread) unless/until one of its "ChordMembers" has been called. Once a ChordMember has been called, the chord will execute some code associated with the member and return a value:

//Any thread can access Add() and Mul(), but only threads which call CalculateNext() will do any processing.
class ThreadedCalculator
{
[ChordMember]
public Add (a : int, b : int) : void;
[ChordMember]
public Mul (a : int, b : int) : void; public CalculateNext () : int
chord {
| Add => a + b
| Mul => a * b
}
}

Calls to ChordMembers are queued for the chord in a "Last In First Out" order.

Interactive Chord Example

More examples can be found at the SVN repository

The using() Construct

  • using (resource) { ... }: This block assures that resource is correctly disposed of even if an exception is thrown. resource must implement the IDisposable interface.

Unchecked Numeric Overflow

  • unchecked { ... }: within the unchecked scope numerical operations will silently overflow
  • checked { ... }: operations will throw an OverflowException like they normally would. Can be used inside of an unchecked context.

Logging Macros

All logging macros/functions 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 the given 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 checked each time the log function is called
  • [assembly: LogFormat (PrependFlag)]: prepends a flag to each message

more...

Profiling Macros

  • [assembly: ProfSetup]: initializes the profiler
  • [Profile] foo () : int { ...}: tells the profiler to include foo
  • [ProfDump] Dump () : void { }: each call to this method will show the profiler's results

more...

SQL Macros

  • [ConfigureConnection (connectionString, name)]: is applied to a class. It tells the compiler about the connections used later on in other SQL macros
  • ExecuteNonQuery ("INSERT INTO employee VALUES ('John', 'Boo')", connection);: executes a query returning no results, via the specified connection
  • def count = ExecuteScalar ("SELECT COUNT FROM employee WHERE firstname = $myparm", connection);: retrieves a query with one result, using the specified connection. Notice how $-notation is used to substitute variables
  • The following executes the given code using every returned result:
ExecuteReaderLoop (
"SELECT * FROM employee WHERE firstname = $myparm",
dbcon,
{
WriteLine($"Name: $firstname $lastname")
}
);

Nemerle Quick Guide的更多相关文章

  1. 29 A Quick Guide to Go's Assembler 快速指南汇编程序:使用go语言的汇编器简介

    A Quick Guide to Go's Assembler 快速指南汇编程序:使用go语言的汇编器简介 A Quick Guide to Go's Assembler Constants Symb ...

  2. (转) Quick Guide to Build a Recommendation Engine in Python

    本文转自:http://www.analyticsvidhya.com/blog/2016/06/quick-guide-build-recommendation-engine-python/ Int ...

  3. Quick guide for converting from JAGS or BUGS to NIMBLE

    Converting to NIMBLE from JAGS, OpenBUGS or WinBUGS NIMBLE is a hierarchical modeling package that u ...

  4. Quick Guide to Microservices with Spring Boot 2.0, Eureka and Spring Cloud

    https://piotrminkowski.wordpress.com/2018/04/26/quick-guide-to-microservices-with-spring-boot-2-0-eu ...

  5. Use swig + lua quick guide

    软件swigwin3    用于生成c的lua包装lua5.2源代码 步骤进入目录G:\sw\swigwin-3.0.12\Examples\lua\arrays执行 SWIG -lua     ex ...

  6. (转) [it-ebooks]电子书列表

    [it-ebooks]电子书列表   [2014]: Learning Objective-C by Developing iPhone Games || Leverage Xcode and Obj ...

  7. Ubuntu Dev Box Setup

    Editor VIM Sublime Atom Visual Studio Code SSH Client PAC Manager File Manager Double Commander Imag ...

  8. [比较老的文章]三维渲染引擎 OGRE 与 OSG 的比较综述

    1 .引言随着计算机可视化.虚拟现实技术的飞速发展,人们对实时真实感渲染以及场景复杂度提出了更高的要求.传统的直接使用底层图形接口如OpenGL.DirectX开发图形应用的模式越来越暴露出开发复杂性 ...

  9. GnuRadio Hacking①:使用GnuRadio+SDR破解固定码无线遥控

    0×01 信号捕获 在这篇文章中,我们将使用GnuRadio+SDR硬件对某品牌型号的无线跳蛋进行无线重放攻击的演示. 市面上常见的无线遥控工作的频段,通常工作在315Mhz.433Mhz,也有少数的 ...

随机推荐

  1. JVM学习笔记(二)------Java代码编译和执行的整个过程【转】

    转自:http://blog.csdn.net/cutesource/article/details/5904542 版权声明:本文为博主原创文章,未经博主允许不得转载. Java代码编译是由Java ...

  2. [Android新手区] SQLite 操作详解--SQL语法

    该文章完全摘自转自:北大青鸟[Android新手区] SQLite 操作详解--SQL语法  :http://home.bdqn.cn/thread-49363-1-1.html SQLite库可以解 ...

  3. crontab实现每秒执行

    crontab: #!/bin/bash step=$1 #每多少秒执行一次 ; i < ; i=(i+step) )); do date +%Y%m%d' '%H:%M:%S >> ...

  4. 如何为github上的项目添加gif效果图

    一.制作gif图片 如何制作可以参考: http://www.jianshu.com/p/27ec6375b8ab?utm_campaign=maleskine&utm_content=not ...

  5. Codeforces 741A:Arpa's loud Owf and Mehrdad's evil plan(LCM+思维)

    http://codeforces.com/problemset/problem/741/A 题意:有N个人,第 i 个人有一个 a[i],意味着第 i 个人可以打电话给第 a[i] 个人,所以如果第 ...

  6. C#:文件、路径(Path_File)

    public class Path_File { public string AppPath { get { return AppDomain.CurrentDomain.BaseDirectory; ...

  7. css不同浏览器兼容性调试 --- 转自: [http://wo.115.com/?ct=detail&id=31733&bid=1018841]

    css不同浏览器兼容性调试 IE6.0,IE7.0与Firefox的CSS兼容性问题1.DOCTYPE 影响 CSS 处理 2.FF: div 设置 margin-left, margin-right ...

  8. Sightseeing tour

    Sightseeing tour Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 8276 Accepted: 3489 Desc ...

  9. THE DRUNK JAILER 分类: POJ 2015-06-10 14:50 13人阅读 评论(0) 收藏

    THE DRUNK JAILER Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 24918   Accepted: 1563 ...

  10. Memcached缓存瓶颈分析

    Memcached缓存瓶颈分析 获取Memcached的统计信息 Shell: # echo "stats" | nc 127.0.0.1 11211 PHP: $mc = new ...