>我正在尝试使用维基教科书上的AwesomeCollections库https://en.wikibooks.org/wiki/F_Sharp_Programming/Advanced_Data_Structures
从该页面,我已将粘贴复制到标记为 .fsi 和 .fs 的 2 个单独文件中的代码中
我必须承认,我不太了解.fsi和.fs文件是如何相互作用的,而且 https://msdn.microsoft.com/en-us/library/dd233196.aspx 上的解释对我来说是神秘的。
通过一些重新格式化,如果我制定解决方案并仅使用 .fs 文件,它可以正常工作。
但是,同时使用 .fsi 和 .fs 文件,我收到错误消息,例如"未定义命名空间'堆'"(在项目的主 .fs 文件中("没有构造函数可用于类型'int BinaryHeap'"(在项目的主.fs文件中(
"实现文件中出现意外的关键字'type'"(尝试在 .fs 文件中定义类型队列时(
(* AwesomeCollections.fsi *)
namespace AwesomeCollections
type 'a stack =
| EmptyStack
| StackNode of 'a * 'a stack
module Stack = begin
val hd : 'a stack -> 'a
val tl : 'a stack -> 'a stack
val cons : 'a -> 'a stack -> 'a stack
val empty : 'a stack
val rev : 'a stack -> 'a stack
end
[<Class>]
type 'a Queue =
member hd : 'a
member tl : 'a Queue
member enqueue : 'a -> 'a Queue
static member empty : 'a Queue
[<Class>]
type BinaryTree<'a when 'a : comparison> =
member hd : 'a
member left : 'a BinaryTree
member right : 'a BinaryTree
member exists : 'a -> bool
member insert : 'a -> 'a BinaryTree
member print : unit -> unit
static member empty : 'a BinaryTree
//[<Class>]
//type 'a AvlTree =
// member Height : int
// member Left : 'a AvlTree
// member Right : 'a AvlTree
// member Value : 'a
// member Insert : 'a -> 'a AvlTree
// member Contains : 'a -> bool
//
//module AvlTree =
// [<GeneralizableValue>]
// val empty<'a> : AvlTree<'a>
[<Class>]
type 'a BinaryHeap =
member hd : 'a
member tl : 'a BinaryHeap
member insert : 'a -> 'a BinaryHeap
member merge : 'a BinaryHeap -> 'a BinaryHeap
interface System.Collections.IEnumerable
interface System.Collections.Generic.IEnumerable<'a>
static member make : ('b -> 'b -> int) -> 'b BinaryHeap
真棒收藏.fs
(* AwesomeCollections.fs *)
namespace AwesomeCollections
type 'a stack =
| EmptyStack
| StackNode of 'a * 'a stack
module Stack =
let hd = function
| EmptyStack -> failwith "Empty stack"
| StackNode(hd, tl) -> hd
let tl = function
| EmptyStack -> failwith "Emtpy stack"
| StackNode(hd, tl) -> tl
let cons hd tl = StackNode(hd, tl)
let empty = EmptyStack
let rec rev s =
let rec loop acc = function
| EmptyStack -> acc
| StackNode(hd, tl) -> loop (StackNode(hd, acc)) tl
loop EmptyStack s
type Queue<'a>(f : stack<'a>, r : stack<'a>) =
let check = function
| EmptyStack, r -> Queue(Stack.rev r, EmptyStack)
| f, r -> Queue(f, r)
member this.hd =
match f with
| EmptyStack -> failwith "empty"
| StackNode(hd, tl) -> hd
member this.tl =
match f, r with
| EmptyStack, _ -> failwith "empty"
| StackNode(x, f), r -> check(f, r)
member this.enqueue(x) = check(f, StackNode(x, r))
static member empty = Queue<'a>(Stack.empty, Stack.empty)
type color = R | B
type 'a tree =
| E
| T of color * 'a tree * 'a * 'a tree
module Tree =
let hd = function
| E -> failwith "empty"
| T(c, l, x, r) -> x
let left = function
| E -> failwith "empty"
| T(c, l, x, r) -> l
let right = function
| E -> failwith "empty"
| T(c, l, x, r) -> r
let rec exists item = function
| E -> false
| T(c, l, x, r) ->
if item = x then true
elif item < x then exists item l
else exists item r
let balance = function (* Red nodes in relation to black root *)
| B, T(R, T(R, a, x, b), y, c), z, d (* Left, left *)
| B, T(R, a, x, T(R, b, y, c)), z, d (* Left, right *)
| B, a, x, T(R, T(R, b, y, c), z, d) (* Right, left *)
| B, a, x, T(R, b, y, T(R, c, z, d)) (* Right, right *)
-> T(R, T(B, a, x, b), y, T(B, c, z, d))
| c, l, x, r -> T(c, l, x, r)
let insert item tree =
let rec ins = function
| E -> T(R, E, item, E)
| T(c, a, y, b) as node ->
if item = y then node
elif item < y then balance(c, ins a, y, b)
else balance(c, a, y, ins b)
(* Forcing root node to be black *)
match ins tree with
| E -> failwith "Should never return empty from an insert"
| T(_, l, x, r) -> T(B, l, x, r)
let rec print (spaces : int) = function
| E -> ()
| T(c, l, x, r) ->
print (spaces + 4) r
printfn "%s %A%A" (new System.String(' ', spaces)) c x
print (spaces + 4) l
type BinaryTree<'a when 'a : comparison> (inner : 'a tree) =
member this.hd = Tree.hd inner
member this.left = BinaryTree(Tree.left inner)
member this.right = BinaryTree(Tree.right inner)
member this.exists item = Tree.exists item inner
member this.insert item = BinaryTree(Tree.insert item inner)
member this.print() = Tree.print 0 inner
static member empty = BinaryTree<'a>(E)
type 'a heap =
| EmptyHeap
| HeapNode of int * 'a * 'a heap * 'a heap
module Heap =
let height = function
| EmptyHeap -> 0
| HeapNode(h, _, _, _) -> h
(* Helper function to restore the leftist property *)
let makeT (x, a, b) =
if height a >= height b then HeapNode(height b + 1, x, a, b)
else HeapNode(height a + 1, x, b, a)
let rec merge comparer = function
| x, EmptyHeap -> x
| EmptyHeap, x -> x
| (HeapNode(_, x, l1, r1) as h1), (HeapNode(_, y, l2, r2) as h2) ->
if comparer x y <= 0 then makeT(x, l1, merge comparer (r1, h2))
else makeT (y, l2, merge comparer (h1, r2))
let hd = function
| EmptyHeap -> failwith "empty"
| HeapNode(h, x, l, r) -> x
let tl comparer = function
| EmptyHeap -> failwith "empty"
| HeapNode(h, x, l, r) -> merge comparer (l, r)
let rec to_seq comparer = function
| EmptyHeap -> Seq.empty
| HeapNode(h, x, l, r) as node -> seq { yield x; yield! to_seq comparer (tl comparer node) }
type 'a BinaryHeap(comparer : 'a -> 'a -> int, inner : 'a heap) =
(* private *)
member this.inner = inner
(* public *)
member this.hd = Heap.hd inner
member this.tl = BinaryHeap(comparer, Heap.tl comparer inner)
member this.merge (other : BinaryHeap<_>) = BinaryHeap(comparer, Heap.merge comparer (inner, other.inner))
member this.insert x = BinaryHeap(comparer, Heap.merge comparer (inner,(HeapNode(1, x, EmptyHeap, EmptyHeap))))
interface System.Collections.Generic.IEnumerable<'a> with
member this.GetEnumerator() = (Heap.to_seq comparer inner).GetEnumerator()
interface System.Collections.IEnumerable with
member this.GetEnumerator() = (Heap.to_seq comparer inner :> System.Collections.IEnumerable).GetEnumerator()
static member make(comparer) = BinaryHeap<_>(comparer, EmptyHeap)
type 'a lazyStack =
| Node of Lazy<'a * 'a lazyStack>
| EmptyStack
module LazyStack =
let (|Cons|Nil|) = function
| Node(item) ->
let hd, tl = item.Force()
Cons(hd, tl)
| EmptyStack -> Nil
let hd = function
| Cons(hd, tl) -> hd
| Nil -> failwith "empty"
let tl = function
| Cons(hd, tl) -> tl
| Nil -> failwith "empty"
let cons(hd, tl) = Node(lazy(hd, tl))
let empty = EmptyStack
let rec append x y =
match x with
| Cons(hd, tl) -> Node(lazy(printfn "appending... got %A" hd; hd, append tl y))
| Nil -> y
let rec iter f = function
| Cons(hd, tl) -> f(hd); iter f tl
| Nil -> ()
maintenance.fs (主程序尝试使用这些库(
///////////////// preparing the data ////////////////////
open System
open System.Collections.Generic
open System.IO
open AwesomeCollections
open AwesomeCollections.Stack
open AwesomeCollections.Heap
let stopWatch = System.Diagnostics.Stopwatch.StartNew()
let x = File.ReadAllLines "C:UsersFaguiDocumentsGitHubLearning FsharpAlgo StanfordPA 6 - median.txt"
let lowheap = new BinaryHeap<int>(compare,EmptyHeap)
let highheap = new BinaryHeap<int>(compare,EmptyHeap)
最后,如果在解决方案中,我决定使用以下文件单独AwesomeCollections_bis.fs(没有FSI文件(代码可以编译。
// this file used without the fsi file works
// but i don't know why
(* AwesomeCollections_bis.fs *)
namespace AwesomeCollections
type 'a stack =
| EmptyStack
| StackNode of 'a * 'a stack
module Stack =
let hd = function
| EmptyStack -> failwith "Empty stack"
| StackNode(hd, tl) -> hd
let tl = function
| EmptyStack -> failwith "Empty stack"
| StackNode(hd, tl) -> tl
let cons hd tl = StackNode(hd, tl)
let empty = EmptyStack
let rec rev s =
let rec loop acc = function
| EmptyStack -> acc
| StackNode(hd, tl) -> loop (StackNode(hd, acc)) tl
loop EmptyStack s
type Queue<'a>(f : stack<'a>, r : stack<'a>) =
let check = function
| EmptyStack, r -> Queue(Stack.rev r, EmptyStack)
| f, r -> Queue(f, r)
member this.hd =
match f with
| EmptyStack -> failwith "empty"
| StackNode(hd, tl) -> hd
member this.tl =
match f, r with
| EmptyStack, _ -> failwith "empty"
| StackNode(x, f), r -> check(f, r)
member this.enqueue(x) = check(f, StackNode(x, r))
static member empty = Queue<'a>(Stack.empty, Stack.empty)
type color = R | B
type 'a tree =
| E
| T of color * 'a tree * 'a * 'a tree
module Tree =
let hd = function
| E -> failwith "empty"
| T(c, l, x, r) -> x
let left = function
| E -> failwith "empty"
| T(c, l, x, r) -> l
let right = function
| E -> failwith "empty"
| T(c, l, x, r) -> r
let rec exists item = function
| E -> false
| T(c, l, x, r) ->
if item = x then true
elif item < x then exists item l
else exists item r
let balance = function (* Red nodes in relation to black root *)
| B, T(R, T(R, a, x, b), y, c), z, d (* Left, left *)
| B, T(R, a, x, T(R, b, y, c)), z, d (* Left, right *)
| B, a, x, T(R, T(R, b, y, c), z, d) (* Right, left *)
| B, a, x, T(R, b, y, T(R, c, z, d)) (* Right, right *)
-> T(R, T(B, a, x, b), y, T(B, c, z, d))
| c, l, x, r -> T(c, l, x, r)
let insert item tree =
let rec ins = function
| E -> T(R, E, item, E)
| T(c, a, y, b) as node ->
if item = y then node
elif item < y then balance(c, ins a, y, b)
else balance(c, a, y, ins b)
(* Forcing root node to be black *)
match ins tree with
| E -> failwith "Should never return empty from an insert"
| T(_, l, x, r) -> T(B, l, x, r)
let rec print (spaces : int) = function
| E -> ()
| T(c, l, x, r) ->
print (spaces + 4) r
printfn "%s %A%A" (new System.String(' ', spaces)) c x
print (spaces + 4) l
type BinaryTree<'a when 'a : comparison> (inner : 'a tree) =
member this.hd = Tree.hd inner
member this.left = BinaryTree(Tree.left inner)
member this.right = BinaryTree(Tree.right inner)
member this.exists item = Tree.exists item inner
member this.insert item = BinaryTree(Tree.insert item inner)
member this.print() = Tree.print 0 inner
static member empty = BinaryTree<'a>(E)
type 'a heap =
| EmptyHeap
| HeapNode of int * 'a * 'a heap * 'a heap
module Heap =
let height = function
| EmptyHeap -> 0
| HeapNode(h, _, _, _) -> h
(* Helper function to restore the leftist property *)
let makeT (x, a, b) =
if height a >= height b then HeapNode(height b + 1, x, a, b)
else HeapNode(height a + 1, x, b, a)
let rec merge comparer = function
| x, EmptyHeap -> x
| EmptyHeap, x -> x
| (HeapNode(_, x, l1, r1) as h1), (HeapNode(_, y, l2, r2) as h2) ->
if comparer x y <= 0 then makeT(x, l1, merge comparer (r1, h2))
else makeT (y, l2, merge comparer (h1, r2))
let hd = function
| EmptyHeap -> failwith "empty"
| HeapNode(h, x, l, r) -> x
let tl comparer = function
| EmptyHeap -> failwith "empty"
| HeapNode(h, x, l, r) -> merge comparer (l, r)
let rec to_seq comparer = function
| EmptyHeap -> Seq.empty
| HeapNode(h, x, l, r) as node -> seq { yield x; yield! to_seq comparer (tl comparer node) }
type 'a BinaryHeap(comparer : 'a -> 'a -> int, inner : 'a heap) =
(* private *)
member this.inner = inner
(* public *)
member this.hd = Heap.hd inner
member this.tl = BinaryHeap(comparer, Heap.tl comparer inner)
member this.merge (other : BinaryHeap<_>) = BinaryHeap(comparer, Heap.merge comparer (inner, other.inner))
member this.insert x = BinaryHeap(comparer, Heap.merge comparer (inner,(HeapNode(1, x, EmptyHeap, EmptyHeap))))
interface System.Collections.Generic.IEnumerable<'a> with
member this.GetEnumerator() = (Heap.to_seq comparer inner).GetEnumerator()
interface System.Collections.IEnumerable with
member this.GetEnumerator() = (Heap.to_seq comparer inner :> System.Collections.IEnumerable).GetEnumerator()
static member make(comparer) = BinaryHeap<_>(comparer, EmptyHeap)
type 'a lazyStack =
| Node of Lazy<'a * 'a lazyStack>
| EmptyStack
module LazyStack =
let (|Cons|Nil|) = function
| Node(item) ->
let hd, tl = item.Force()
Cons(hd, tl)
| EmptyStack -> Nil
let hd = function
| Cons(hd, tl) -> hd
| Nil -> failwith "empty"
let tl = function
| Cons(hd, tl) -> tl
| Nil -> failwith "empty"
let cons(hd, tl) = Node(lazy(hd, tl))
let empty = EmptyStack
let rec append x y =
match x with
| Cons(hd, tl) -> Node(lazy(printfn "appending... got %A" hd; hd, append tl y))
| Nil -> y
let rec iter f = function
| Cons(hd, tl) -> f(hd); iter f tl
| Nil -> ()
我可以看到缩进很重要,我认为使用它可以解决问题,但它不适合我。
感谢任何人的慷慨帮助!
我认为您的代码不编译的原因是fsi
接口文件隐藏了BinaryHeap
的构造函数,因此以下内容不起作用,因为构造函数是私有的:
let highheap = new BinaryHeap<int>(compare,EmptyHeap)
该类型公开了一个make
静态成员,因此我认为您可以改用它:
let highheap = BinaryHeap.make compare
这可能不是特别惯用的 F# 设计,但我想它主要是一个示例而不是维护库。FSharpX 集合库中可能有一些替代方案。