在F#元组中使用CustomComparison和CustomEquality实现自定义比较 [英] Implementing custom comparison with CustomComparison and CustomEquality in F# tuple
问题描述
我在这里要问一个特定的话题-我确实在网络上找不到关于此的信息. 我正在实现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)中获得具有最大静态值的叶子,我认为实现CompareTo
或Equals
将使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.
实现CompareTo
或Equals
的通常方法是仅比较存储在类型中的某些值.例如,您可以编写如下内容:
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屋!