我在ocaml的递归不可改变的数据结构可以简化为这样的事:扩展不变类型(或:恒定类型快速缓存)OCaml中
type expr =
{
eexpr : expr_expr;
some_other_complex_field : a_complex_type;
}
and expr_expr =
| TInt of int
| TSum of (expr * expr)
| TMul of (expr * expr)
这是一个AST,有时它会非常复杂(非常深)。
有一个递归函数来评估表达式。例如,让我们说,
let rec result expr =
match expr.eexpr with
| TInt i -> i
| TSum (e1, e2) -> result e1 + result e2
| TMul (e1, e2) -> result e1 * result e2
现在假设我映射到另一个表达式,我需要不断地检查一个expr的结果,有时不止一次同EXPR,有时为表达式最近使用模式
{ someExpr with eexpr = TSum(someExpr, otherExpr) }
现在映射,结果功能是非常轻巧,但运行它多次为深AST不会非常优化。我知道我可以使用Hashtbl来缓存这个值,但是AFAIK Hashtbl只会做结构上的平等,所以它无论如何都需要遍历我的长期AST。 我知道最好的选择是在expr类型中包含一个可能不可变的“结果”字段。但我不能。
那么Ocaml有什么方法可以将一个值缓存到一个不可变的类型,所以我不需要每次需要时都急切地计算它呢?
谢谢!
谢谢,Jeffrey为此作出了巨大的回应!所以最有可能我可以做一个列表和一个函数,将查找与==然后列表相同的行为? 我在ocaml手册上读到物理相等对不可变结构有未定义的行为,虽然它保证当A == B时A = B(当然)。当我使用模式{expr与eexpr = TAdd(expr,otherExpr)}时,是否保证在TAdd(thisExpr,_)thisExpr == expr? – Waneck 2012-02-03 11:26:00
散列表比列表工作得更好,因为它将按近似的结构相等性(即通常的散列函数)排序为分箱。除非你的所有值在结构上相等,否则这比只使用一个列表要好。 (你可以定制你的散列函数来查看最经常变化的部分。)就像我说的,我认为(==)不变值的语义对你而言是可以的。对于什么是(==)没有强有力的保证,运行时允许用纯粹的值任意地巧妙(FP是如此酷的一个原因)。但在实践中,我会说是。 – 2012-02-03 17:13:11
哦,我明白了!但是,每次哈希值都需要遍历大的AST,不是吗?我的“结果”函数是相当轻量级的,所以也许它比慢慢地调用它要慢,不是吗? – Waneck 2012-02-03 17:42:20