Comparison Of Nemerle and F# For Functional On .Net

后端 未结 2 1809
北海茫月
北海茫月 2021-02-19 15:22

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 adv

2条回答
  •  北荒
    北荒 (楼主)
    2021-02-19 15:38

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

提交回复
热议问题