简体   繁体   English

F#名称空间和模块:Wikibooks上的绝妙收藏

[英]F# namespaces and modules : Awesome collections from Wikibooks

I'm trying to use the library AwesomeCollections on Wikibooks https://en.wikibooks.org/wiki/F_Sharp_Programming/Advanced_Data_Structures 我正在尝试在Wikibooks https://zh.wikibooks.org/wiki/F_Sharp_Programming/Advanced_Data_Structures上使用库AwesomeCollections

From that page, i have copied paste in 2 separate files code marked for .fsi and .fs 从该页面,我复制了粘贴到标记为.fsi和.fs的2个单独文件中的代码

I must admit i don't understand well how .fsi and .fs files interact, and that explanations such those found on https://msdn.microsoft.com/en-us/library/dd233196.aspx are cryptic to me. 我必须承认,我不太了解.fsi和.fs文件是如何交互的,并且对https://msdn.microsoft.com/zh-cn/library/dd233196.aspx上的解释是很神秘的。

with a bit of re-formating, if i make a solution and use only the .fs file, it works fine. 稍微重新格式化一下,如果我提出一个解决方案,只使用.fs文件,它就可以正常工作。

However, using both the .fsi and .fs file, i get Error message such as "the namespace 'Heap' is not defined" (in the main .fs file of the project) "No constructors are available for the type 'int BinaryHeap'" (in the main .fs file of the project) 但是,同时使用.fsi和.fs文件,会出现错误消息,例如“未定义命名空间'Heap'”(在项目的主.fs文件中)“类型'int BinaryHeap没有可用的构造函数。 '”(在项目的主.fs文件中)

"Unexpected keyword 'type' in implementation file" (when trying to define the type Queue in the .fs file) “实现文件中的意外关键字'type'”(尝试在.fs文件中定义类型Queue时)

(* 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

AwesomeCollections.fs AwesomeCollections.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 (main program trying to use those libraries) 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:\Users\Fagui\Documents\GitHub\Learning Fsharp\Algo Stanford\PA 6 - median.txt"

let lowheap = new BinaryHeap<int>(compare,EmptyHeap)
let highheap = new BinaryHeap<int>(compare,EmptyHeap)

Finally if in the solution, I decide to use the following file AwesomeCollections_bis.fs alone (no fsi file) the code will compile ok. 最后,如果在解决方案中,我决定单独使用以下文件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 -> ()

i can see indentation is important and I thought playing with it would solve the problem, but it didn't for me. 我可以看到缩进很重要,我认为使用缩进可以解决问题,但对我而言不是。

Thank you for anyone graciously helping ! 谢谢您的慷慨帮助!

I think that the reason why your code is not compiling is that the fsi interface file hides the constructor of BinaryHeap , so the following does not work because the constructor is private: 我想,为什么你的代码不编译原因是fsi接口文件隐藏的构造BinaryHeap ,所以下面不起作用,因为构造函数是专用:

let highheap = new BinaryHeap<int>(compare,EmptyHeap)

The type exposes a make static member so I think you can use that instead: 该类型公开了一个make静态成员,因此我想可以改用它:

let highheap = BinaryHeap.make compare

This is probably not particularly idiomatic F# design, but I guess it is mostly a sample rather than a maintained library. 这可能不是特别惯用的F#设计,但我想它主要是示例而不是维护的库。 There might be some alternatives in FSharpX Collections library. FSharpX Collections库中可能有一些替代方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM