我在这里遇到了一个小问题。我写了Tortoise and Hare cycle detection algorithm。
type Node =
| DataNode of int * Node
| LastNode of int
let next node =
match node with
|DataNode(_,n) -> n
|LastNode(_) -> failwith "Error"
let findCycle(first) =
try
let rec fc slow fast =
match (slow,fast) with
| LastNode(a),LastNode(b) when a=b -> true
| DataNode(_,a), DataNode(_,b) when a=b -> true
| _ -> fc (next slow) (next <| next fast)
fc first <| next first
with
| _ -> false
这对
非常有用 let first = DataNode(1, DataNode(2, DataNode(3, DataNode(4, LastNode(5)))))
findCycle(first)
显示错误。对。现在,当试图测试一个循环时,我无法创建循环!
显然这不会起作用:
let first = DataNode(1, DataNode(2, DataNode(3, DataNode(4, first))))
但我需要那样的东西!你能告诉我如何创建一个吗?
答案 0 :(得分:3)
您定义的类型不能对您的类型执行此操作。有关可行的替代方法,请参见How to create a recursive data structure value in (functional) F#?。
作为Brian解决方案的替代方案,您可以尝试以下方式:
type Node =
| DataNode of int * NodeRec
| LastNode of int
and NodeRec = { node : Node }
let rec cycle = DataNode(1, { node =
DataNode(2, { node =
DataNode(3, { node =
DataNode(4, { node = cycle}) }) }) })
答案 1 :(得分:1)
这是一种方式:
type Node =
| DataNode of int * Lazy<Node>
| LastNode of int
let next node = match node with |DataNode(_,n) -> n.Value |LastNode(_) -> failwith "Error"
let findCycle(first) =
try
let rec fc slow fast =
match (slow,fast) with
| LastNode(a),LastNode(b) when a=b->true
| DataNode(a,_), DataNode(b,_) when a=b -> true
| _ -> fc (next slow) (next <| next fast)
fc first <| next first
with
| _ -> false
let first = DataNode(1, lazy DataNode(2, lazy DataNode(3, lazy DataNode(4, lazy LastNode(5)))))
printfn "%A" (findCycle(first))
let rec first2 = lazy DataNode(1, lazy DataNode(2, lazy DataNode(3, lazy DataNode(4, first2))))
printfn "%A" (findCycle(first2.Value))
答案 2 :(得分:0)
即使Brian和kvb都发布了有效的答案,我仍然觉得我需要看看是否有可能以不同的方式实现同样的目标。此代码将为您提供包含为Seq&lt;'a&gt;
的循环结构type Node<'a> = Empty | Node of 'a * Node<'a>
let cyclic (n:Node<_>) : _ =
let rn = ref n
let rec next _ =
match !rn with
| Empty -> rn := n; next Unchecked.defaultof<_>
| Node(v, x) -> rn := x; v
Seq.initInfinite next
let nodes = Node(1, Node(2, Node(3, Empty)))
cyclic <| nodes |> Seq.take 40 // val it : seq<int> = seq [1; 2; 3; 1; ...]
结构本身不是循环的,但它从外面看起来像。
或者你可以这样做:
//removes warning about x being recursive
#nowarn "40"
type Node<'a> = Empty | Node of 'a * Lazy<Node<'a>>
let rec x = Node(1, lazy Node(2, lazy x))
let first =
match x with
| Node(1, Lazy(Node(2,first))) -> first.Value
| _ -> Empty
答案 3 :(得分:0)
你能告诉我如何创建吗?
在F#中有各种黑客来获取直接循环值(正如Brian和kvb所示),但我注意到这很少是你真正想要的。直接循环数据结构是一个可以调试的猪,通常用于性能,因此变得可变。
例如,您的循环图可能表示为:
> Map[1, 2; 2, 3; 3, 4; 4, 1];;
val it : Map<int,int> = map [(1, 2); (2, 3); (3, 4); (4, 1)]
在F#中表示图形的惯用方法是存储从句柄到顶点映射的字典,如果需要,还存储另一个用于边缘的字典。这种方法更容易调试,因为您通过可理解的查找表遍历间接递归,而不是尝试解密堆中的图形。但是,如果你想让GC收集无法访问的子图,那么弱哈希映射的纯功能替代方案显然是计算机科学中尚未解决的问题。