需求明确了接下来就是实现,iScheme 的逻辑操作实现如下:
.BuildIn("and", (args, scope) => {
(args.Length > 0).OrThrows();
return !args.Any(arg => !(SBool)arg.Evaluate(scope));
})
.BuildIn("or", (args, scope) => {
(args.Length > 0).OrThrows();
return args.Any(arg => (SBool)arg.Evaluate(scope));
})
.BuildIn("not", (args, scope) => {
(args.Length == 1).OrThrows();
return args[0].Evaluate(scope);
})
比较操作
iScheme 的比较操作包括 = < > >= <= ,需要注意下面几点:
= 是比较操作而非赋值操作。同算术操作一样,它们应用于数值类型,并支持任意数量的参数。
= 的实现如下:
.BuildIn("=", (args, scope) => {
(args.Length > 1).OrThrows("Must have more than 1 argument in relation operation.");
SNumber current = (SNumber)args[0].Evaluate(scope);
foreach (var arg in args.Skip(1)) {
SNumber next = (SNumber)arg.Evaluate(scope);
if (current == next) {
current = next;
} else {
return false;
}
}
return true;
})
可以预见所有的比较操作都将使用这段逻辑,因此把这段比较逻辑抽象成一个扩展方法:
public static SBool ChainRelation(this SExpression[] expressions, SScope scope, Func<SNumber, SNumber, Boolean> relation) {
(expressions.Length > 1).OrThrows("Must have more than 1 parameter in relation operation.");
SNumber current = (SNumber)expressions[0].Evaluate(scope);
foreach (var obj in expressions.Skip(1)) {
SNumber next = (SNumber)obj.Evaluate(scope);
if (relation(current, next)) {
current = next;
} else {
return SBool.False;
}
}
return SBool.True;
}
接下来就可以很方便的定义比较操作:
.BuildIn("=", (args, scope) => args.ChainRelation(scope, (s1, s2) => (Int64)s1 == (Int64)s2))
.BuildIn(">", (args, scope) => args.ChainRelation(scope, (s1, s2) => s1 > s2))
.BuildIn("<", (args, scope) => args.ChainRelation(scope, (s1, s2) => s1 < s2))
.BuildIn(">=", (args, scope) => args.ChainRelation(scope, (s1, s2) => s1 >= s2))
.BuildIn("<=", (args, scope) => args.ChainRelation(scope, (s1, s2) => s1 <= s2))
注意 = 操作的实现里面有 Int64 强制转型——因为我们没有重载 SNumber#Equals ,所以无法直接通过 == 来比较两个 SNumber 。
列表操作
iScheme 的列表操作包括 first , rest , empty? 和 append ,分别用来取列表的第一个元素,除第一个以外的部分,判断列表是否为空和拼接列表。
first 和 rest 操作如下:










