views:

217

answers:

2

Hi all,

Community Wiki Question:

Pursuant to this question: What are the benefits of using Scala in .Net? another question comes to mind. Can anyone lay out the comparative advantages (and disadvantages) of Nemerle and F# for functional development on the .Net platform? I've just looked at Nemerle in passing. It sounds like it kind of plays in the same ballpark as F# so I was wondering what differences there are other than the obvious syntax differences and the big advantage F# has of being backed by Microsoft.

+2  A: 

I know little about Nemerle, but I think one of its big features is macros (a la hygenic Scheme-like happy macros, as opposed to ugly C-like macros). I never quite grokked why people love macros so much, but then again, I never grokked why people like algebraic data types and pattern-matching so much, until I started using F#. So I suspect that if you love macros, and you use .NET, then you're a rabid Nemerle fan.

Brian
Mmm, pattern matching. I wonder how tasty scheme like happy macros are. Now I must try Nermerle over the weekend.
gradbot
Nemerle macros are, basically, compiler extensions. They are used to implement most of the language constructs, including 'if' statements and 'for' loops, Linq support, and various useful libraries for logging, profiling, AOP, etc.
Don Reba
@Brian: "I never quite grokked why people love macros so much". Given you know F#, try OCaml's macros (camlp4).
Jon Harrop
+10  A: 

I’ve touched both these languages and my impressions on Nemerle are briefly the following:(I assume that most of the audience is familiar with F# and Nemerle is less popular so for the sake of fairness I'll cover it a bit more):

  • F# community is rather big and it grows constantly due to large number of blogposts, articles etc. Also it is spreaded across the countries. As the opposite, Nemerle enthusiasts are basically russian-speaking and concentrated on RSDN.ru site.
  • Nemerle syntax is IMO much friendlier for developers with background in C-like languages.
  • Nemerle (as well as F#) has type inference features. Type inference mechanism in Nemerle is bound to method body (local functions, variables and so on), opposing to F# global type inference scope. However Nemerle compiler doesn’t enforce any specific idioms of writing code to assist type inference mechanism.

F#

open System.Text

let l = [1; 2; 3]
let r1 = l |> List.fold(fun (sb : StringBuilder) v -> sb.Append(v).AppendLine()) (StringBuilder()) // type annotation is required on the function argument
let r2 = (StringBuilder(), l) ||> List.fold(fun sb v -> sb.Append(v).AppendLine()) //here compiler can infer type of State parameter 

Nemerle

using System.Console; 
using System.Collections.Generic; 
using System.Text; 

def l = [1,2,3]; 
def res = l.FoldLeft(StringBuilder(), (v, acc) => acc.Append(v).AppendLine()); 
WriteLine($"Result:\n$res"); 

def d = Dictionary(); // generic parameters are absent (even placeholders!!!) 
d.Add(1, "!"); 
WriteLine(d.GetType()); // System.Collections.Generic.Dictionary`2[System.Int32,System.String] 

Also you may notice another feature of Nemerle compiler – it can infer types from further usage. To deduce types F# uses approach based on Hindley-Milner algorithm and tries to infer most generic type. Nemerle, in opposite, never infers polymorphic types and always looks for most specific type.

F#

let addInt = (+) 5
let addString = (+) "!!!"

let run f x = f (f x) // ('T -> 'T) -> 'T -> 'T

run addInt 5
run addString "S"

Nemerle in the same conditions will infer type of run as (int->int) * int -> int.

More details on Nemerle type inference mechanism can be found in MSc thesis of Michal Moskal: Type Inference With Deferral

  • Nemerle has rich metaprogramming capabilities. Most of language control constructs, like loops, conditional expressions, LINQ support, forthcoming feature of parsing included C# sources and many more – all of them are created using macros. One sample of macros applications can be found here. BTW, string formatting capabilities with $ syntax in the sample above - is also the built-in macro.

EDIT: Added slightly larger sample

using System.Console;
using System.Collections.Generic;
using System.Text;

variant Expr
{
  | Const { value : double }
  | Var { name : string }
  | Operation { id : string; left : Expr; right : Expr }

  public Eval(operations : Dictionary[string, double*double -> double], context : Dictionary[string, double]) : double
  {
    match(this)
    {
        | Const (value) => value
        | Var(name) => context[name]
        | Operation(id, left, right) => 
            def f = operations[id];
            f(left.Eval(operations, context), right.Eval(operations, context))
    }
  }
}

module Program
{
    public Main() : void
    {
        def expr = 
            Expr.Operation(
                "*",
                Expr.Const(10),
                Expr.Operation(
                "+",
                Expr.Var("n"),
                Expr.Const(5)
                )
            );
        def operations = Dictionary.[string, double * double -> double]();
        operations["+"] = (x, y) => x + y;
        operations["*"] = _ * _;

        def vars = Dictionary();
        vars["n"] = 3.0;

        def result = expr.Eval(operations, vars);
        WriteLine($"Result is $result");
    }
}
desco