在F#元组中使用CustomComparison和CustomEquality实现自定义比较 [英] Implementing custom comparison with CustomComparison and CustomEquality in F# tuple

查看:76
本文介绍了在F#元组中使用CustomComparison和CustomEquality实现自定义比较的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在这里要问一个特定的话题-我确实在网络上找不到关于此的信息. 我正在实现F#版本的Minimax算法.我现在遇到的问题是我想比较我的树的叶子(下面的数据结构).在搜索VS给我的错误时,我发现了这样的东西:

I'm here to ask a specific topic - I really found few info about this on the web. I'm implementing a F# version of Minimax algorithm. The problem I'm having now is that I want to compare Leaf of my tree (data structure below). Searching the erros the VS gave to me I arrived to something like this:

我曾经拥有的树类型:

type TreeOfPosition =
    | LeafP   of Position
    | BranchP of Position * TreeOfPosition list

以及实现IComparable的诱惑

and the temptative for implementing the IComparable

type staticValue = int
[<CustomEquality;CustomComparison>]
type TreeOfPosition =
    | LeafP   of Position * staticValue
    | BranchP of Position * TreeOfPosition list

    override x.Equals(yobj) = 
        match yobj with
        | :? TreeOfPosition as y -> (x = y)
        | _ -> false

    override x.GetHashCode() = hash (x)
    interface System.IComparable with
        member x.CompareTo yobj =
            match yobj with
            | :? TreeOfPosition as y -> compare (x) (y)
            | _ -> invalidArg "yobj" "cannot compare value of different types"

最后,我只想通过其静态值(在其他函数中计算)来获取LeafP列表的最大值(和最小值).

In the end, I just wanna get the max (and the min) of a list of LeafP by its static value (calculate in other function).

上面的代码进行编译.但是,用此方法进行测试:

The code above compiles. However testing with this:

let p = new Position()
p.Add(1,BLACK)
let a = LeafP(p,1)
let b = LeafP(p,2)

let biger = compare a b
printf "%d" biger

我在GetHashCode覆盖的"|:?TreeOfPosition as y->比较(x)(y)"行中得到了System.StackOverflowException.

I got a System.StackOverflowException in the "| :? TreeOfPosition as y -> compare (x) (y)" line in the override of the GetHashCode.

我在hubfs.net中有一个线程( http://cs.hubfs. net/forums/thread/15891.aspx ),我正在讨论我的Minimax.在这里,您可以找到我的最新代码( http://www.inf.ufrgs. br/〜pmdusso/works/Functional_Implementation_Minimax_FSharp.htm )

I have a thread in the hubfs.net (http://cs.hubfs.net/forums/thread/15891.aspx) with I'm discussing my Minimax. Here you can find my lastest code (http://www.inf.ufrgs.br/~pmdusso/works/Functional_Implementation_Minimax_FSharp.htm)

谢谢,

Pedro Dusso

Pedro Dusso

嗯,我很清楚地知道了这个主意,但我无法使它生效.记住我想从叶子列表("List.max":P)中获得具有最大静态值的叶子,我认为实现CompareToEquals将使List.max对它们起作用,正确的? 我是这样写的:

Well, I understood very clearly the idea but I can’t make it work. Remembering that I want to get the leaf with the max static value from a list of leafs ("List.max" :P), I think implementing the CompareTo or Equals will let the List.max works on them, correct? I compose the things like this:

let mycompare x y = 
  match x, y with
  // Compare values stored as part of your type
  | LeafP(_, n1), LeafP(_, n2) -> compare n1 n2
  //| BranchP(_, l1), BranchP(_, l2) -> compare l1 l2 //I do not need Branch lists comparison
  | _ -> 0 // or 1 depending on which is list...

[< CustomEquality;CustomComparison >]
type TreeOfPosition =
    | LeafP   of Position * int
    | BranchP of Position * TreeOfPosition list

    override x.Equals(yobj) = 
       match yobj with
       | :? TreeOfPosition as y -> (x = y)
       | _ -> false

    override x.GetHashCode() = hash (x)
    interface System.IComparable with
       member x.CompareTo yobj = 
          match yobj with 
          | :? TreeOfPosition as y -> mycompare x y
          | _ -> invalidArg "yobj" "cannot compare value of different types" 

我以这种方式安排功能的问题是:

The problems I’m having arranging the functions this way is:

1)未定义模式识别符"LeafP"(带红色下划线的LeafP)

1) The pattern discriminator 'LeafP' is not defined (with LeafP red-underlined)

2)(77,39):错误FS0039:未定义值或构造函数"mycompare",当我尝试按ALT ENTER键时,此消息出现在我的F#Interactive中.位置{77,39}对应于mycompare调用的开始(在GetHashCode中).

2) (77,39): error FS0039: The value or constructor 'mycompare' is not defined, when I try a ALT ENTER this message appear in my F# Interactive. The position {77,39} corresponds to the beginning of mycompare call (in GetHashCode).

我做错了什么?我能做得更好吗?

What I’m doing wrong? What can I do better?

非常感谢

Pedro Dusso

Pedro Dusso

编辑3-已解决

是的!我会设法解决您的最终定稿!

Yes! I manage your answer to work finaly!

最终代码在这里:

[<CustomEquality;CustomComparison>]
type TreeOfPosition =
    | LeafP   of Position * int
    | BranchP of Position * TreeOfPosition list

    //Func: compare
    //Retu: -1: first parameter is less than the second
    //       0: first parameter is equal to the second
    //       1: first parameter is greater than the second
    static member mycompare (x, y) = 
        match x, y with
        // Compare values stored as part of your type
        | LeafP(_, n1), LeafP(_, n2) -> compare n1 n2
        | _ -> 0 // or 1 depending on which is list...

    override x.Equals(yobj) = 
        match yobj with
        | :? TreeOfPosition as y -> (x = y)
        | _ -> false

    override x.GetHashCode() = hash (x)
    interface System.IComparable with
       member x.CompareTo yobj = 
          match yobj with 
          | :? TreeOfPosition as y -> TreeOfPosition.mycompare(x, y)
          | _ -> invalidArg "yobj" "cannot compare value of different types" 

感谢您的反馈!

Pedro Dusso

Pedro Dusso

推荐答案

首先,由于compare函数调用要比较的值的CompareTo方法(即x.ComaperTo(y)).在CompareTo的自定义实现中使用compare进行比较的值是要求您(在运行时)进行比较的值,因此这会导致堆栈溢出.

First of all, you're getting the exception because the compare function calls the CompareTo method of the values you're comparing (that is x.ComaperTo(y)). The values you're comparing using compare in the custom implementation of CompareTo are the values that the you are asked to compare (by the runtime), so this causes the stack overflow.

实现CompareToEquals的通常方法是仅比较存储在类型中的某些值.例如,您可以编写如下内容:

The usual way to implement CompareTo or Equals is to compare only some values that you store in your type. For example, you could write something like this:

编辑:您可以编写一个辅助函数mycopare进行比较(或者可以简单地更改CompareTo实现).但是,如果要使用函数,则需要将其移动到类型声明中(这样它就可以知道类型-请注意,在F#中,声明的顺序很重要!)

EDIT: You can write a helper function mycopare to do the comparison (or you could simply change the CompareTo implementation). However, if you want to use a function, you need to move it inside the type declaration (so that it knows about the type - note that in F#, the order of declaration matters!)

一种书写方式是这样:

[<CustomEquality; CustomComparison >] 
type TreeOfPosition = 
  | LeafP   of Position * int 
  | BranchP of Position * TreeOfPosition list 

  override x.Equals(yobj) =  
     match yobj with 
     | :? TreeOfPosition as y -> 
        // TODO: Check whether both y and x are leafs/branches
        // and compare their content (not them directly)
     | _ -> false 
  override x.GetHashCode() = // TODO: hash values stored in leaf/branch

  interface System.IComparable with 
     member x.CompareTo yobj =  

       // Declare helper function inside the 'CompareTo' member
       let mycompare x y = 
         match x, y with
         // Compare values stored as part of your type
         | LeafP(_, n1), LeafP(_, n2) -> compare n1 n2
         | BranchP(_, l1), BranchP(_, l2) -> compare l1 l2
         | _ -> -1 // or 1 depending on which is list...

       // Actual implementation of the member
       match yobj with 
       | :? TreeOfPosition as y -> mycompare x y
       | _ -> invalidArg "yobj" "cannot compare value of different types" 

之所以可行,是因为每次对compare的调用仅占用部分数据,因此您正在取得一些进展.

This would work, because every call to compare takes only some part of the data, so you're making some progress.

这篇关于在F#元组中使用CustomComparison和CustomEquality实现自定义比较的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆