βusing System;
using System.Collections.Generic;
using System.Linq;
IExpr rule = new Or(new HasTag("article"), new And(new HasTag("video"), new HasTag("captioned")));
foreach (var tags in new[]
{
new HashSet<string> { "article" },
new HashSet<string> { "video" },
new HashSet<string> { "video", "captioned" }
}) Console.WriteLine(rule.Eval(tags));
interface IExpr { bool Eval(IReadOnlySet<string> tags); }
sealed record HasTag(string Tag) : IExpr
{
public bool Eval(IReadOnlySet<string> tags) => tags.Contains(Tag);
}
sealed record And(IExpr Left, IExpr Right) : IExpr
{
public bool Eval(IReadOnlySet<string> tags) => Left.Eval(tags) && Right.Eval(tags);
}
sealed record Or(IExpr Left, IExpr Right) : IExpr
{
public bool Eval(IReadOnlySet<string> tags) => Left.Eval(tags) || Right.Eval(tags);
}
+using System;
using System.Collections.Generic;
using System.Linq;
IExpr rule = new Or(new HasTag("article"), new And(new HasTag("video"), new HasTag("captioned")));
foreach (var tags in new[]
{
new HashSet<string> { "article" },
new HashSet<string> { "video" },
new HashSet<string> { "video", "captioned" }
}) Console.WriteLine(rule.Eval(tags));
// Different expression kinds evaluate the same input to a boolean result.
interface IExpr { bool Eval(IReadOnlySet<string> tags); }
sealed record HasTag(string Tag) : IExpr
{
public bool Eval(IReadOnlySet<string> tags) => tags.Contains(Tag);
}
// Delegate to child expressions and own only the combination rule.
sealed record And(IExpr Left, IExpr Right) : IExpr
{
public bool Eval(IReadOnlySet<string> tags) => Left.Eval(tags) && Right.Eval(tags);
}
sealed record Or(IExpr Left, IExpr Right) : IExpr
{
public bool Eval(IReadOnlySet<string> tags) => Left.Eval(tags) || Right.Eval(tags);
}