Nemerle Quick Guide
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 laterdef 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, soa = b = c
is not allowed- Compound assignment is allowed:
a += b;
- Compound assignment is allowed:
+
: addition and string/list concatenation-, *, /, %
: subtraction/multiplication/division/moduloa <-> b;
: swap (exchanges the values of a and b)++, --
: adds/subtracts 1 to/from a value
Logical Operators
==, !=
: equal/not equalx.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 theEquals
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 idef 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 Examplemodule 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 withDllImportAttribute
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 namedSum
, getting the value from the fieldsum
. 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 propertySumOfSam
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.AssertionException
will 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.
Namespaces
Namespaces are objects which may hold classes, modules, and other namespaces.
namespace SomeSpace { ... }
: declares a new namespaceusing SomeSpace;
: opens the namespace (All objects inSomeSpace
are now in scope)using System.Console;
: opens the type, making its static methods visibleusing 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.
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 statedclass Example[T] where T : class {...}
: T must be a reference typeclass Example[T] where T : struct {...}
: T must be a value typeclass Example[T] where T : enum {...}
: T must be an enumeration typeclass 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 listdef numbers = [1, 2, 3];
: creates a list with the values between the bracketsdef more_numbers = 4 :: numbers;
: :: adds a new item to the listdef 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
Useful Properties on Lists
Length : int
: the length of the listHead : T
: the first element in the listLast : T
: the last element in the listTail : 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 listChopFirstN(int : n) : list[t]
: returns the list without the first N elementsLastN(int : n) : list[t]
: returns the last N elements of the listReverse() : list[T]
: returns the reversed listRemove(item : T) : list[T]
: returns the list with all instances ofitem
removedContains(item : T) : bool
returns true/false if the list does/doesn't containitem
Iter (f : T -> void) : void
: calls the given function using each element in the list as an argumentMap (f : T -> T') : list[T']
: executesf
using each element in thelist[T]
and returns the results as a newlist[T']
Sort (cmp : T * T -> int)
: returns a new sorted list. Equality is determined byf
, a function which compares twoT
s 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 alist[list[T]]
where each sub-list contains all elements which are considered equal. Equality is determined as inSort()
FoldLeft(acc : T', f : T*T' -> T') : T'
: returns the result of executingf
recursively on the list. more detailsFoldRight(acc : T', f : T*T' -> T') : T'
: likeFoldLeft()
, but works through the list backwards.ForAll (f : T -> bool) : bool
: returns true iff
returns true for all items in the listExists (f : T -> bool) : bool
: returns true iff
returns true for any item in the listFind (pred : T -> bool) : Option[T]
: returns, as an option, the first elementpred
returns true withFilter (pred : T -> bool) : list[T]
: returns a new list containing all elementspred
returns true withRemoveDuplicates() : void
: removes duplicate elementsToArray() : 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 elementsdef b = array(2, 3)
: specifies the number of elements in a multi-dimensional arraydef c = array[1, 2, 3]
: initializes with the specified elementsdef 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 parenthesesint*string*char
: is the type of the above tupledef 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
andSecond
retrieve the first or second element of the tuple, respectivelySwap
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 optionsdef 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 3def t : int? = null;
: declares a new nullable int whose value is nullwhen (t != null) {...}
: is the same aswhen (t.HasValue) {...}
a = b ?? -1;
:a
is set to the wrapped value ofb
ifb
isn't null. Otherwise,a
is set to the value after the two question marksa = b?.P;
: ReturnsP
ifb
is not null. Otherwise returns the default value ofP
)'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 accessSome.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 codeunless (condition) code
: if condition is false, then execute codeif (condition) code1 else code2
: if condition is true, then execute code1. Otherwise, execute code2
Loops
while (condition) code
: execute code while condition is truedo code while (condition)
: the same as above, but checks the condition at the end of the code, so it is always run at least oncefor (mutable i = 0; i < 10; i++) code
: A standard C-style for-loop.foreach (i in $[0..9]) code
like the above, using a rangeforeach (i in $[9,8..0]) code
reverse orderforeach (x in list) code
: execute the code for every member x of the enumerable collection listforeach (x in list with index) code
: like the above with available collection indexforeach (x when x != null in list) code
: like the above but only for members which aren't nullrepeat (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");
: ifcondition
is false, an AssertionException will be thrown
Imperative Programming and Blocks
To use return
, break
and continue
the Nemerle.Imperative
namespace must be used:
return x;
: stops the execution of a function/method/property and returns xbreak;
: stops the execution of a loop and moves on to the next bit of codecontinue;
: 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
}
The Nemerle Standard Library
Collection Classes
The Nemerle Collection classes/interfaces are all contained in the Nemerle.Collections
namespace.
Many of these classes extend items from the .NET Collections library with useful methods like Iter
, Fold
, and Map
:
ICollection[T]
: extendsSystem.Collections.ICollection[T]
Hashtable[K, V]
: extendsSystem.Collections.Generic.Dictionary[K, V]
Stack[T]
: extendsSystem.Collections.Stack
LinkedList[T]
: extendsSystem.Collections.GenericLinkedList[T]
Queue[T]
: extendsSystem.Collections.Queue[T]
Others provide additional functionality:
Tree
an implentation of the Red-Black tree data structureRList
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 oflist
's operations as well as:Sum
: adds two sets yielding only one replica of each duplicated elementSubtract
: returns all elements of the first set that are not in the second oneIntersect
: return the elements that appear on both setsXor
: 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 $-notationscanf(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 usedsomeFunction([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));
}
}
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)
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 and can be used with strings, lists, arrays, etc without worrying about their type. If the object does not contain aLength
member, an exception will be thrown during runtime.late o.Name.[1]
: calls the default indexer on o.Name. You should be aware that callingo.Name.Chars[1]
calls the indexer namedChars
ono.Name
.
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 typedef f1 = Foo(f);
: creates a delegate containing the method/functionf
def f2 = Foo( fun(i, s) { ... } );
: creates a delegate containing an anonymous functionevent MyEvent : Foo;
: creates an event field of delegate type FooFoo += method;
: adds a method to the delegateFoo -= method;
: removes a method from the delegateFoo(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 forobject
.object
is usuallythis
.
Concurrency Macros
The following macros are contained in the Nemerle.Concurrency
namespace:
async { ... }
: executes a block of code asynchronouslyasync 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.
More examples can be found at the SVN repository
The using() Construct
using (resource) { ... }
: This block assures thatresource
is correctly disposed of even if an exception is thrown.resource
must implement theIDisposable
interface.
Unchecked Numeric Overflow
unchecked { ... }
: within the unchecked scope numerical operations will silently overflowchecked { ... }
: operations will throw anOverflowException
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 flagslog (VERB, "example", 2)
: calls the logging function, if the compilation flag is set, with the given parameterswhenlogging (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
Profiling Macros
[assembly: ProfSetup]
: initializes the profiler[Profile] foo () : int { ...}
: tells the profiler to includefoo
[ProfDump] Dump () : void { }
: each call to this method will show the profiler's results
SQL Macros
[ConfigureConnection (connectionString, name)]
: is applied to a class. It tells the compiler about the connections used later on in other SQL macrosExecuteNonQuery ("INSERT INTO employee VALUES ('John', 'Boo')", connection);
: executes a query returning no results, via the specified connectiondef 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的更多相关文章
- 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 ...
- (转) Quick Guide to Build a Recommendation Engine in Python
本文转自:http://www.analyticsvidhya.com/blog/2016/06/quick-guide-build-recommendation-engine-python/ Int ...
- 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 ...
- 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 ...
- Use swig + lua quick guide
软件swigwin3 用于生成c的lua包装lua5.2源代码 步骤进入目录G:\sw\swigwin-3.0.12\Examples\lua\arrays执行 SWIG -lua ex ...
- (转) [it-ebooks]电子书列表
[it-ebooks]电子书列表 [2014]: Learning Objective-C by Developing iPhone Games || Leverage Xcode and Obj ...
- Ubuntu Dev Box Setup
Editor VIM Sublime Atom Visual Studio Code SSH Client PAC Manager File Manager Double Commander Imag ...
- [比较老的文章]三维渲染引擎 OGRE 与 OSG 的比较综述
1 .引言随着计算机可视化.虚拟现实技术的飞速发展,人们对实时真实感渲染以及场景复杂度提出了更高的要求.传统的直接使用底层图形接口如OpenGL.DirectX开发图形应用的模式越来越暴露出开发复杂性 ...
- GnuRadio Hacking①:使用GnuRadio+SDR破解固定码无线遥控
0×01 信号捕获 在这篇文章中,我们将使用GnuRadio+SDR硬件对某品牌型号的无线跳蛋进行无线重放攻击的演示. 市面上常见的无线遥控工作的频段,通常工作在315Mhz.433Mhz,也有少数的 ...
随机推荐
- JVM学习笔记(二)------Java代码编译和执行的整个过程【转】
转自:http://blog.csdn.net/cutesource/article/details/5904542 版权声明:本文为博主原创文章,未经博主允许不得转载. Java代码编译是由Java ...
- [Android新手区] SQLite 操作详解--SQL语法
该文章完全摘自转自:北大青鸟[Android新手区] SQLite 操作详解--SQL语法 :http://home.bdqn.cn/thread-49363-1-1.html SQLite库可以解 ...
- crontab实现每秒执行
crontab: #!/bin/bash step=$1 #每多少秒执行一次 ; i < ; i=(i+step) )); do date +%Y%m%d' '%H:%M:%S >> ...
- 如何为github上的项目添加gif效果图
一.制作gif图片 如何制作可以参考: http://www.jianshu.com/p/27ec6375b8ab?utm_campaign=maleskine&utm_content=not ...
- 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] 个人,所以如果第 ...
- C#:文件、路径(Path_File)
public class Path_File { public string AppPath { get { return AppDomain.CurrentDomain.BaseDirectory; ...
- 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 ...
- Sightseeing tour
Sightseeing tour Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 8276 Accepted: 3489 Desc ...
- 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 ...
- Memcached缓存瓶颈分析
Memcached缓存瓶颈分析 获取Memcached的统计信息 Shell: # echo "stats" | nc 127.0.0.1 11211 PHP: $mc = new ...