4

私はF#を初めて使用し、基本を学びます。

2つのモジュールがあります。と呼ばれるツリーデータ構造の一般的なものTree

module Tree

let rec getDescendants getChildren node  = 
    seq { yield node
          for child in getChildren node do 
            yield! getDescendants getChildren child }

let isLeaf getChildren node = Seq.isEmpty (getChildren node)

let getLeaves getChildren node = getDescendants getChildren node  
                               |> Seq.filter (isLeaf getChildren)

ご覧のとおり、すべての関数にはgetChildren引数があります。これは、特定のタイプのノードの子を列挙する関数です。

2番目のモジュールは、XMLツリーのより具体的なケースを処理します。

module XmlTree

open System.Xml.Linq

let getXmlChildren (node : XElement) = node.Elements()

let getDescendants = Tree.getDescendants getXmlChildren 
let getLeaves = Tree.getLeaves getXmlChildren 
let isLeaf = Tree.isLeaf getXmlChildren 

XMLノードの特定のgetXmlChildren関数が定義され、カレー関数に渡されTreeます。

現在、コードの重複が非常に多くなっています。

どういうわけか次のことを行うことは可能ですか?(擬似コード)

module XmlTree = Tree with getChildren = fun (node : XElement) -> node.Elements()
4

2 に答える 2

11

F#はファンクターをサポートしていないため、F#モジュールにパラメーターを渡すことはできません。あなたの例では、ノードの子を生成する関数をオブジェクトコンストラクターに渡すだけで十分です。

type Tree<'T>(childFn: 'T -> 'T seq) =
    let getChildren = childFn

    member x.getDescendants node  = 
        seq { yield node
              for child in getChildren node do 
                yield! x.getDescendants child }

    member x.isLeaf node = node |> getChildren |> Seq.isEmpty
    member x.getLeaves node = node |> x.getDescendants |> Seq.filter x.isLeaf

// Type usage
open System.Xml.Linq
let xmlTree = new Tree<XElement>(fun x -> x.Elements())

より洗練されたケースでは、継承が進むべき道です。Tree<'T>特に、抽象メンバーを持つ抽象クラスとして宣言し、サブクラスgetChildrenでそのメソッドをオーバーライドできます。XmlTree

于 2012-05-14T11:22:12.480 に答える
5

これはモジュールではなく、ジェネリックなどで行います。

編集

type tree<'t>(Children:seq<tree<'t>>)=

    member x.isLeaf()  = Seq.isEmpty (Children )

    member x.getLeaves() = 
        getDescendants Children
        |> Seq.filter (fun x -> x.isLeaf())

getdescendantsを省略しましたが、それで十分です。また、一部の型注釈は必須ではありませんが、何が起こっているかを示しています

于 2012-05-14T09:58:42.380 に答える