La implementación de comparación personalizada con CustomComparison y CustomEquality en Fa # tupla
-
29-09-2019 - |
Pregunta
Estoy aquí para pedir un tema específico - Realmente encontraron información sobre esto en la web. Estoy poniendo en práctica una versión # F del algoritmo Minimax. El problema que estoy teniendo ahora es que quiero comparar la hoja de mi árbol (estructura de datos más adelante). Búsqueda de los erros el VS me dio a mí llegué a algo como esto:
El tipo de árbol que solía tener:
type TreeOfPosition =
| LeafP of Position
| BranchP of Position * TreeOfPosition list
y el temptative para la realización del 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"
Al final, sólo quiero llegar al máximo (y el min) de una lista de LeafP por su valor estático (calcule en función de otra).
El código anterior compila. Sin embargo la prueba con esto:
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
Tengo una System.StackOverflowException en el "|:? TreeOfPosition como Y -> comparar (x) (y)". Línea en la anulación de la GetHashCode
I tiene un hilo en el hubfs.net ( http: //cs.hubfs. / foros / hilo neta / 15891.aspx ) con el que estoy discutiendo mi Minimax. Aquí puede encontrar el código de lastest ( http: //www.inf.ufrgs. br / ~ pmdusso / obras / Functional_Implementation_Minimax_FSharp.htm )
Gracias de antemano,
Pedro Dusso
Bueno, me entiende muy claramente la idea, pero no puedo hacer que funcione. Recordando que quiero conseguir la hoja con el valor estático máximo de una lista de hojas ( “List.max”: P), creo que la aplicación de la CompareTo
o Equals
permitirá que el List.max trabaja en ellos, ¿verdad?
Compongo las cosas como esto:
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"
Los problemas que tengo la organización de las funciones de esta manera es:
1) El discriminador patrón 'LeafP' no está definido (con LeafP subrayada en rojo)
2) (77,39): error FS0039: El valor o constructor 'mycompare' no está definido, cuando intento una ALT ENTER este mensaje aparece en mi F # interactivo. La posición {77,39} corresponde al comienzo de la llamada mycompare (en GetHashCode).
Lo que estoy haciendo mal? ¿Qué puedo hacer mejor?
Muchas gracias,
Pedro Dusso
EDITAR 3 - Resuelto
Sí! Administro su respuesta al trabajo finaly!
El código final está aquí:
[<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"
Gracias por los comentarios!
Pedro Dusso
Solución
En primer lugar, que está recibiendo la excepción ya que la función compare
llama al método CompareTo
de los valores que se está comparando (que es x.ComaperTo(y)
). Los valores que se está comparando el uso de compare
en la implementación personalizada de CompareTo
son los valores que el se le pide que compare (por el tiempo de ejecución), así que esto hace que el desbordamiento de pila.
La forma más habitual de implementar CompareTo
o Equals
es comparar sólo algunos valores que se almacenan en su tipo. Por ejemplo, podría escribir algo como esto:
Editar : Puede escribir un mycopare
función auxiliar para hacer la comparación (o simplemente podría cambiar la implementación CompareTo
). Sin embargo, si desea utilizar una función, es necesario moverlo dentro de la declaración de tipo (para que sepa sobre el tipo - nota de que en C #, el orden de los asuntos de declaración)
Una forma de escribirlo es la siguiente:
[<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"
Esto funcionaría, ya que cada llamada a compare
toma sólo una parte de los datos, por lo que está haciendo algunos progresos.