open System
open System.Collections.Generic
type Node<'a>(expr:'a, symbol:int) =
member x.Expression = expr
member x.Symbol = symbol
override x.GetHashCode() = symbol
override x.Equals(y) =
match y with
| :? Node<'a> as y -> symbol = y.Symbol
| _ -> failwith "Invalid equality for Node."
interface IComparable with
member x.CompareTo(y) =
match y with
| :? Node<'a> as y -> compare symbol y.Symbol
| _ -> failwith "Invalid comparison for Node."
type Ty =
| Int
| String
| Tuple of Ty list
| Rec of Node<Ty>
| Union of Ty list
type NodeDict<'a> = Dictionary<'a,Node<'a>>
let get_nodify_tag =
let mutable i = 0
fun () -> i <- i+1; i
let nodify (dict: NodeDict<_>) x =
match dict.TryGetValue x with
| true, x -> x
| false, _ ->
let x' = Node(x,get_nodify_tag())
dict.[x] <- x'
x'
let d = Dictionary(HashIdentity.Structural)
let nodify_ty x = nodify d x
let rec int_string_stream =
Union
[
Tuple [Int; Rec (nodify_ty (int_string_stream))]
Tuple [String; Rec (nodify_ty (int_string_stream))]
]
在上面的示例中,int_string_stream
给出了类型错误,但它巧妙地说明了我想要做的事情。当然,我希望双方都在symbol
中使用相同的nodify_ty
标记。当我尝试将Rec
类型更改为Node<Lazy<Ty>>
时,我发现它没有正确地比较它们,并且每一方都得到一个对我来说无用的新符号。
我正在研究一种语言,到目前为止我处理存储递归类型的方法是将Rec
映射到int
,然后用相关的{{1}替换它在我需要的时候在字典中。目前,我正在清理语言,并希望Ty
案例为Rec
,而不是Node<Ty>
。
此时此刻,我不确定我还能在这里尝试什么。这可以以某种方式完成吗?
答案 0 :(得分:2)
我认为你需要在代表你的类型的歧视联盟中添加某种形式的明确“延迟”。如果没有明确的延迟,您将始终完全评估类型,因此没有可能关闭循环。
这样的事似乎有效:
type Ty =
| Int
| String
| Tuple of Ty list
| Rec of Node<Ty>
| Union of Ty list
| Delayed of Lazy<Ty>
// (rest is as before)
let rec int_string_stream = Delayed(Lazy.Create(fun () ->
Union
[
Tuple [Int; Rec (nodify_ty (int_string_stream))]
Tuple [String; Rec (nodify_ty (int_string_stream))]
]))
这意味着当您在Ty
上进行模式匹配时,您将始终需要检查Delayed
,评估延迟值,然后再次模式匹配,但这可能是可行的!