تنفيذ المقارنة المخصصة مع CustomComparison و CustomEfection في F# tuple
-
29-09-2019 - |
سؤال
أنا هنا لأطلب موضوعًا محددًا - لقد وجدت حقًا بعض المعلومات حول هذا الموضوع على الويب. أنا أقوم بتنفيذ إصدار F# من خوارزمية Minimax. المشكلة التي أواجهها الآن هي أنني أريد مقارنة ورقة الشجر (بنية البيانات أدناه). البحث عن erros أعطاه VS لي وصلت إلى شيء من هذا القبيل:
نوع الشجرة الذي اعتدت أن يكون لدي:
type TreeOfPosition =
| LeafP of Position
| BranchP of Position * TreeOfPosition list
والإغراء لتنفيذ 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"
في النهاية ، أريد فقط الحصول على الحد الأقصى (و MIN) لقائمة من LeafP من خلال قيمته الثابتة (حساب في وظيفة أخرى).
الرمز أعلاه يجمع. لكن الاختبار مع هذا:
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
حصلت على نظام. stackoverflowexception في خط "|:؟ treeofposition كـ y -> قارن (x) (y)" في تجاوز GethashCode.
لدي موضوع في hubfs.net (http://cs.hubfs.net/forums/thread/15891.aspx) مع أناقش الحد الأدنى الخاص بي. هنا يمكنك العثور على آخر رمز لي (http://www.inf.ufrgs.br/~pmdusso/works/functional_implementation_minimax_fsharp.htm)
شكرا مقدما،
بيدرو دوسو
حسنًا ، لقد فهمت الفكرة بوضوح تامة ، لكنني لا أستطيع أن أجعلها تعمل. أتذكر أنني أريد الحصول على الورقة ذات القيمة الساكنة القصوى من قائمة الأوراق ("list.max": p) ، أعتقد أن تطبيق CompareTo
أو Equals
هل ستدع القائمة. max يعمل عليها ، صحيح؟ أقوم بتأليف أشياء مثل هذا:
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"
المشكلات التي أواجهها في ترتيب الوظائف بهذه الطريقة هي:
1) لم يتم تعريف تمييز النمط "Leafp" (مع Leafp Red-Underlined)
2) (77،39): خطأ FS0039: لا يتم تعريف القيمة أو المنشئ "MyCompare" ، عندما أحاول ظهور هذه الرسالة تظهر في F# التفاعلية. يتوافق الموضع {77،39} مع بداية مكالمة MyCompare (في GethashCode).
ماذا أفعل خطأ؟ ماذا يمكنني أن أفعل بشكل أفضل؟
شكرا جزيلا،
بيدرو دوسو
تحرير 3 - حل
نعم! أدير إجابتك على العمل النهائي!
الرمز النهائي هنا:
[<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"
شكرا على ملاحظاتك!
بيدرو دوسو
المحلول
بادئ ذي بدء ، أنت تحصل على الاستثناء لأن compare
الدالة تستدعي CompareTo
طريقة القيم التي تقارنها (وهذا هو x.ComaperTo(y)
). القيم التي تقارنها باستخدام compare
في التنفيذ المخصص لـ CompareTo
هي القيم التي يُطلب منك مقارنتها (حسب وقت التشغيل) ، لذلك يؤدي هذا إلى تجاوز الفائض.
الطريقة المعتادة للتنفيذ CompareTo
أو Equals
هو مقارنة بعض القيم التي تقوم بتخزينها فقط في النوع الخاص بك. على سبيل المثال ، يمكنك كتابة شيء مثل هذا:
تعديل: يمكنك كتابة وظيفة المساعد mycopare
لإجراء المقارنة (أو يمكنك ببساطة تغيير CompareTo
تطبيق). ومع ذلك ، إذا كنت ترغب في استخدام وظيفة ، فأنت بحاجة إلى نقلها داخل إعلان النوع (بحيث يعرف عن النوع - لاحظ أنه في F#، أمر الإعلان مهم!)
طريقة واحدة للكتابة هي:
[<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
لا تأخذ سوى جزء من البيانات ، لذلك فأنت تحرز بعض التقدم.