Implementazione di confronto personalizzato con CustomComparison e CustomEquality in F # tuple
-
29-09-2019 - |
Domanda
Sono qui per chiedere a un argomento specifico - ho davvero trovato poche informazioni su questo sul web. Sto implementando una versione F # dell'algoritmo Minimax. Il problema che sto avendo ora è che voglio mettere a confronto Foglia del mio albero (struttura dei dati di seguito). Cercando le erros VS ha dato a me sono arrivato a qualcosa di simile:
Il tipo di albero che ho usato per avere:
type TreeOfPosition =
| LeafP of Position
| BranchP of Position * TreeOfPosition list
e il temptative per l'attuazione 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"
Alla fine, voglio solo ottenere il massimo (e la min) di un elenco di LeafP dal suo valore statico (calcolare in altra funzione).
Il codice sopra compila. Tuttavia il test con questo:
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
Ho una System.StackOverflowException nel "|:? TreeOfPosition come y -> confrontare (x) (y)". Riga l'override del GetHashCode
Ho un thread nel hubfs.net ( http: //cs.hubfs. / forum / thread net / 15891.aspx ) con sto discutendo il mio Minimax. Qui potete trovare il mio codice di lastest ( http: //www.inf.ufrgs. br / ~ pmdusso / opere / Functional_Implementation_Minimax_FSharp.htm )
Grazie in anticipo,
Pedro Dusso
Bene, ho capito molto chiaramente l'idea, ma non riesco a farlo funzionare. Ricordando che voglio ottenere la foglia con il valore massimo da un elenco statico di foglie ( “List.max”: P), penso che l'attuazione del CompareTo
o Equals
farà si che il List.max lavora su di loro, giusto?
Compongo le cose in questo modo:
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"
I problemi che sto avendo organizzando le funzioni in questo modo è:
1) Il pattern discriminatore 'LeafP' non è definito (con LeafP rosso-sottolineato)
2) (77,39): l'errore FS0039: Il valore o il costruttore 'mycompare' non è definito, quando provo un ALT INVIO questo messaggio appare nella mia F # Interactive. La posizione {77,39} corrisponde all'inizio della chiamata mycompare (in GetHashCode).
Quello che sto facendo di sbagliato? Cosa posso fare di meglio?
Grazie mille,
Pedro Dusso
EDIT 3 - Risolto
Sì! Riesco la tua risposta al lavoro finalmente!
Il codice finale è qui:
[<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"
Grazie per il feedback!
Pedro Dusso
Soluzione
Prima di tutto, stai diventando l'eccezione poiché la funzione compare
chiama il metodo CompareTo
dei valori si sta confrontando (che è x.ComaperTo(y)
). I valori si sta confrontando con compare
nella realizzazione personalizzata di CompareTo
sono i valori che la viene chiesto di confrontare (dal runtime), quindi questo fa sì che l'overflow dello stack.
Il solito modo per implementare CompareTo
o Equals
è quello di confrontare solo alcuni valori che si memorizzare nel vostro tipo. Ad esempio, si potrebbe scrivere qualcosa di simile:
Modifica : È possibile scrivere una funzione di supporto mycopare
per fare il confronto (o si può semplicemente cambiare l'implementazione CompareTo
). Tuttavia, se si desidera utilizzare una funzione, è necessario spostare all'interno della dichiarazione del tipo (in modo che conosce il tipo - Si noti che in F #, l'ordine delle questioni dichiarazione)
Un modo di scrivere è questo:
[<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"
Questo potrebbe funzionare, perché ogni chiamata a compare
richiede solo una parte dei dati, in modo che stai facendo qualche progresso.