我已经实现了一些函数的天真评估器。我刚刚进入f#的世界,所以它会问你存在(如果是的话,如何实现)更快的评估者。我必须得到一个包含(variableName,(condition + newVariableName))的数据结构。这两个字段是字符串。以下是我的评估者版本的一部分:
let env = new Dictionary<_,_>(HashIdentity.Structural)
//eval: expr -> Prop
let rec eval = function
//Val of string -- is a variable name or a string value
| Val e -> if e.Equals("TRUE") then True // True is a Prop type used for BDD Algorithm
elif e.Equals("FALSE") then False // False is a Prop type used for BDD Algorithm
else var e //var of string --- is a Prop type used for BDD Algorithm
| Int i -> var (i.ToString())
| Float e -> var (e.ToString())
| Const c -> var c //Const of string --- is a constant name (ex. "$foo" is a constant)
| Path (e, s) -> var ((eval e).ToString() + "." + s)
| Lookup(s, el) -> var s
| Integer(ex) -> eval ex
| FromTo (e, el) ->var ((eval e).ToString() + (eval el.Head).ToString() + (eval el.Tail.Head).ToString())
| Str(e) -> eval e
| Equality (v, e) -> let evalV = eval v
let evalE = eval e
match evalE with
| Var e ->
let sndKey = "Equality" + evalE.ToString()
if env.ContainsKey (evalV.ToString()) then
if env.[(evalV.ToString())].Equals(sndKey) then
var env.[(evalV.ToString())]
else ~~~ (var env.[(evalV.ToString())])
else
env.Add((evalV.ToString()), (evalV.ToString()) + sndKey)
var ((evalV.ToString()) + sndKey)
| _ as k -> if bddBuilder.Equiv k False then
let sndKey = "Equality" + "False"
if env.ContainsKey (evalV.ToString()) then
if env.[(evalV.ToString())].Equals(sndKey) then
var env.[(evalV.ToString())]
else ~~~ (var env.[(evalV.ToString())])
else
env.Add((evalV.ToString()), (evalV.ToString()) + sndKey)
var ((evalV.ToString()) + sndKey)
else let sndKey = "Equality" + "True"
if env.ContainsKey (evalV.ToString()) then
if env.[(evalV.ToString())].Equals(sndKey) then
var env.[(evalV.ToString())]
else ~~~ (var env.[(evalV.ToString())])
else
env.Add((evalV.ToString()), (evalV.ToString()) + sndKey)
var ((evalV.ToString()) + sndKey)
| Inequality (v, e) -> let evaluatedV = (eval v).ToString()
let evaluatedE = (eval e).ToString()
let sndKey = "Inequality" + evaluatedE
if env.ContainsKey (evaluatedV.ToString()) then
if env.[(evaluatedV.ToString())].Equals(sndKey) then
var env.[(evaluatedV.ToString())]
else ~~~ (var env.[(evaluatedV.ToString())])
else env.Add((evaluatedV.ToString()), (evaluatedV.ToString()) + sndKey)
var ((evaluatedV.ToString()) + sndKey)
| IfThenElse (e1, e2, e3) -> (eval e1 &&& eval e2) ||| ((~~~ (eval e1)) &&& eval e3)
| FindString(e1, e2) -> var ("FS" + (eval e1).ToString() + (eval e2).ToString())
| GreaterThan(e1, e2) -> let evaluatedV = (eval e1).ToString()
let evaluatedE = (eval e2).ToString()
let sndKey = "GreaterThan" + evaluatedE
if env.ContainsKey (evaluatedV.ToString()) then
if env.[(evaluatedV.ToString())].Equals(sndKey) then
var env.[(evaluatedV.ToString())]
else ~~~ (var env.[(evaluatedV.ToString())])
else env.Add((evaluatedV.ToString()), (evaluatedV.ToString()) + sndKey)
var ((evaluatedV.ToString()) + sndKey)
| GreaterThanOrEqual(e1, e2) -> let evaluatedV = (eval e1).ToString()
let evaluatedE = (eval e2).ToString()
let sndKey = "GreaterThanOrEqual" + evaluatedE
if env.ContainsKey (evaluatedV.ToString()) then
if env.[(evaluatedV.ToString())].Equals(sndKey) then
var env.[(evaluatedV.ToString())]
else ~~~ (var env.[(evaluatedV.ToString())])
else env.Add((evaluatedV.ToString()), (evaluatedV.ToString()) + sndKey)
var ((evaluatedV.ToString()) + sndKey)
| Null(e) -> var ("Null" + (eval e).ToString())
| GetToken(e1, e2, e3) -> var ((eval e1).ToString() + (eval e2).ToString())
| Mod(e1, e2) -> var ((eval e1).ToString() + (eval e2).ToString())
| Match(e1, e2) -> let evaluatedV = (eval e1).ToString()
let evaluatedE = (eval e2).ToString()
let sndKey = "Match" + evaluatedE
if env.ContainsKey (evaluatedV.ToString()) then
if env.[(evaluatedV.ToString())].Equals(sndKey) then
var env.[(evaluatedV.ToString())]
else ~~~ (var env.[(evaluatedV.ToString())])
else env.Add((evaluatedV.ToString()), (evaluatedV.ToString()) + sndKey)
var ((evaluatedV.ToString()) + sndKey)
| LessThenOrEqual(e1, e2) -> let evaluatedV = (eval e1).ToString()
let evaluatedE = (eval e2).ToString()
let sndKey = "LessThen" + evaluatedE
if env.ContainsKey (evaluatedV.ToString()) then
if env.[(evaluatedV.ToString())].Equals(sndKey) then
var env.[(evaluatedV.ToString())]
else ~~~ (var env.[(evaluatedV.ToString())])
else env.Add((evaluatedV.ToString()), (evaluatedV.ToString()) + sndKey)
var ((evaluatedV.ToString()) + sndKey)
| LessThen(e1, e2) -> let evaluatedV = (eval e1).ToString()
let evaluatedE = (eval e2).ToString()
let sndKey = "LessThen" + evaluatedE
if env.ContainsKey (evaluatedV.ToString()) then
if env.[(evaluatedV.ToString())].Equals(sndKey) then
var env.[(evaluatedV.ToString())]
else ~~~ (var env.[(evaluatedV.ToString())])
else env.Add((evaluatedV.ToString()), (evaluatedV.ToString()) + sndKey)
var ((evaluatedV.ToString()) + sndKey)
| Length(e) -> var ("Len" + (eval e).ToString())
| Full(e) -> var ("Full" + (eval e).ToString())
| Minus(e1, e2) -> var ((eval e1).ToString() + (eval e2).ToString())
| Times(e1, e2) -> var ((eval e1).ToString() + (eval e2).ToString())
| Plus (e1, e2) -> var ((eval e1).ToString() + (eval e2).ToString())
| Duration(e) -> eval e
| Minutes(e) -> eval e
| Trim(e) -> var ("Tri" + (eval e).ToString())
| Reverse(e) -> var ("Rev" + (eval e).ToString())
| Ast.And (v1, v2) -> eval v1 &&& eval v2
| Ast.Or (v1, v2) -> eval v1 ||| eval v2
| Ast.Not(v1) -> ~~~ (eval v1)
| _ as a-> failwithf "Expression %A not found" a
编辑:此评估程序用于验证布尔条件。在这个版本中只有一个字典,它的性能更高,但我如何模拟以下情况:
答案 0 :(得分:1)
答案是:这取决于。
在某些情况下,最好在你去的时候天真地走树。当你的表达式很小并且只评估一次或只评估几次时,这可能是最好的策略。
如果你的表情很大并且可能会被评估,也许最好尝试做一些优化。任何优化都会产生需要分摊的相关成本,因此这就是为什么最好定位需要多次执行的大表达式。您可以尝试多种类型的优化,这里有一些建议(一个好的编译器教科书无疑会有更多更好的建议):
您实施的任何优化都应该根据'naïve'基线进行仔细测量,在某些情况下,您的优化可能不会按预期运行,并可能导致执行速度变慢。
其他任何非常简单的优化都可能非常难以实现,祝你好运!
答案 1 :(得分:0)
对您的代码进行最简单的优化可能会产生显着的收益,可能会替换您使用(可怕的)F#扩展方法来搜索Dictionary
并使用未分配的.NET替代方法。所以这个:
match env.TryGetValue evaluatedV with
| true, v1 ->
match v1.TryGetValue sndKey with
| true, v2 -> v2
| _ ->
v1.[sndKey] <- evaluetedV + sndKey
env.[evaluatedV] <- v1
evaluatedV + sndKey
| _ ->
if value.Count <> 0 then value.Clear()
value.[sndKey] <- evaluetedV + sndKey
env.[evaluatedV] <- value
evaluatedV + sndKey
变为:
let mutable v1 = Unchecked.defaultof<_>
if env.TryGetValue(evaluatedV, &v1) then
let mutable v2 = Unchecked.defaultof<_>
if v1.TryGetValue(sndKey, &v2) then v2 else
v1.[sndKey] <- evaluetedV + sndKey
env.[evaluatedV] <- v1
evaluatedV + sndKey
else
if value.Count <> 0 then value.Clear()
value.[sndKey] <- evaluetedV + sndKey
env.[evaluatedV] <- value
evaluatedV + sndKey
但是,这些哈希表查找可能会破坏您的性能。有各种各样的技术可以避免这些问题,但它们不是F#特定的:
value
或env
词典中查找该符号的结果。