我接触过这两种语言,对 Nemerle 的印象简要如下:(我假设大多数观众都熟悉 F#,而 Nemerle 不太受欢迎,所以为了公平起见,我会多介绍一些):
- F# 社区相当大,并且由于大量的博客文章、文章等而不断增长。而且它分布在各个国家/地区。相反,Nemerle 爱好者基本上都讲俄语,并且专注于RSDN.ru http://rsdn.ru/forum/nemerle site.
- 在我看来,Nemerle 语法对于具有类 C 语言背景的开发人员来说更加友好。
- Nemerle(以及 F#)具有类型推断功能。 Nemerle 中的类型推断机制绑定到方法体(局部函数、变量等),与 F# 全局类型推断作用域相反。然而,Nemerle 编译器并不强制执行任何特定的代码编写习惯来辅助类型推断机制。
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]
此外,您可能会注意到 Nemerle 编译器的另一个功能 - 它可以从进一步的使用中推断出类型。为了推断类型,F# 使用基于 Hindley-Milner 算法的方法并尝试推断最通用的类型。相反,Nemerle 从不推断多态类型,并且总是寻找最具体的类型。
F#
let addInt = (+) 5
let addString = (+) "!!!"
let run f x = f (f x) // ('T -> 'T) -> 'T -> 'T
run addInt 5
run addString "S"
Nemerle 在相同条件下会推断出类型runas (int->int) * int -> int。
关于 Nemerle 类型推理机制的更多细节可以参见 Michal Moskal 的硕士论文:延迟类型推断 http://research.microsoft.com/en-us/um/people/moskal/pdf/msc.pdf
- Nemerle 拥有丰富的元编程能力。大多数语言控制结构,如循环、条件表达式、LINQ 支持、即将推出的解析功能(包括 C# 源代码等等)——所有这些都是使用宏创建的。可以找到一个宏应用程序示例here http://v2matveev.blogspot.com/2010/08/inotifypropertychanged-strikes-back.html。顺便说一句,字符串格式化功能$上面示例中的语法 - 也是内置宏。
EDIT:添加了稍大的样本
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");
}
}