Last active
April 16, 2019 15:27
-
-
Save vbfox/370bbb41cc4bb51d289f53dea7c71547 to your computer and use it in GitHub Desktop.
Prototype of Equals function for F# Fable React interop that does the same as the (=) operator except that all functions are equal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Flawed try, I don't think a deep function ignoring compare is practical | |
// | |
// https://fable.io/repl/#?code=PYBwpgdgBAYghgIwDZgHQEkC2JgCcAuqAUgMoCwAUKJLIiqgMJ5pEDO6E+Yuol108ZGia4wlSgG0APFhwEAFACIwARwCucJAEFcuOAE9WAdQCW+ABaKANFEUAzOmAC0SEwj259AegCq+E0ioAFasigCUAHwAupQo+FAguCYAbnBcUKoa2roGxmbmUPIAHgBcUMAIQWGF+mUVVYUAxth1lVBOEeVtHVAIwMBIYWV9A1AAvJRQU1AhAHJpKWIUkjLYePhKjcDYcKIAImlgoTb2ji5uHt5+AcGhkTEUcQlJqelbO-uHrIWlXQ3ytT+QygJk440m0zmC2SSxWAFFMGYlAASAAM4zGUGRAEZwtFYmB4okUocZqw4epNN9ilBWv99LSgYyRkhxmT5v4YeIKNIEUjFGioABCTE4vEPJ7E15gdnAfAUrLUoqM+rVAEqyrVYb9VmYqGc2GPQnPEnpVhwTBgAAq+nAPzpasBqvBFGmsvllKQ3wZEDUSFZADIAxC3VN6qgAEpgOzcSCNMAKqnyEOht0AeUqYEahAA5oSAAo8fBy21gNN2YphAD8WwgrHwuDU2bwVhTqamGaCWdzBaLJfA5YB1dr9cbzdwYW5vMRG0U+FLwDsWNR4oJRJepJCNvAi8KAH0NQ0yqPQTm2frFlOpHzZ4LQfW4BB47uDlxV0b16aZSZWK+ZfIDwdZkdXPVgOUvZYPxBCBXAgGUpVJH8dD0BliiAiZXWmZCDFQJCcgZZUAB9CKgbD9AAITUOwY1wXDWAANRMMAAHcoCKblJQ3dJRC2XAABNCzlfsZQw9NM2zVA83wQTi3nAcKwAbxIzBdgAa24NkGzUGVCIAX0nSCnh4k1pRBVgo14vj7SZUTphMJcQkTL02KgX1-SgCxIDbaYHC9JY3TAPzvKmTihLZTtu0k3shLkssKyKAz20KcMoxouME09Vh5B4vABL7WKbESITEvbYizIs3LnmKjjjWMhDuKzXKnOpVhArsID5DlcxuHQlN7L+SNo1jJ8MsVeRWqQOwbC67hqk8iBgo8xt-OmQLWpBJcIDlQpzUtbcZQmpcZonDzuoWzDU181qUzWlbUyeCwf3mS1vkxCKJPUwxxrakr7uNFAIBzCxNPMJ6LSORhgDUThFqeTA1HwRwQTZVFYeNeHEaEKBRFYP14kxLS7tDRbmNBlBkakKAAaBgog2xo48agPjgEWt0HtBsDwZBsGXtQCQTAeJK3RMKApCcZGAGooGxbkhemJ5DvozRtLZQ6q3kR7OctX6haeY6laQFXMWO9XNeesAdaS-qtvieRMipKBFeVmV9eduaztZ9sccZsWoCuomksW72kHwblHys+3nLQpkAV6i6NoG1LhvjZrihsfR3a8+O3UJm6-ITxzMpctzWXmxbC8VKAfT9JA8-W-qK4d6v3LL7OfKpInboL1h9t3ZVMXsaHsxMYAIEUU6s6SrwvFgIf-FH75dhlEcTD42MI6LhBCWYsAaDAOBGnMRbp-KTzcEd4BTrSJmfxANJD6gRpH16eC4FYVqrLsURAv0cue4XJcDIB52DniPMeddvwOX-juJcyopCdEUPUbs49W5JX9hAhOP4Kr8Rcqg9sJ8fDrTgI7cAjQTCaHppZR+2w76iHPveLgcArK7k8kzaMcA8bHxnqPGUxYoBqHWprDIRc15gBAEgX+bcphYMajghkdMcr8Wai5SRAV84N2gWAPuVZlHANAaPFBHspFsR0ZlIcGD+p4RQrgoxVtWBkSrlAOmkcyJ5GBsqBkkdWAWKXD+P8NjJ7tj8aSeRAYmg0KXn+b4HiUY6y7ifK0aY9hpjKFExa6DIKxRMqSLQbIFJVzKKCeIulKBZPqjKcieSCnQWKTVT8pl+5QCUo4zEAAmKAek1zZPSEAppJFentM6ZBYknA7DQEUAAUi0OPeQMiqEJUoCM-AYzbBTJmXMyqGdFlJFGeMtZhQNk4PyVoVAvSACs+lKAjgGGgJAwAczyHej2aS+VSzlj6S0qAZyOmXIoNc+gdyHlPKii8mKbylzHNOWyC5BklkrMUE4JwihtlFPhYTKA+y7ZF2VM0gZPzYU7OWeM-2GLpmFC8S5XFbIADM+KUW7NsCSzFFKcWkShW0qAvy4XEo7qSmZFL8nkXZVAdpukmlsrxVywlaLlp8vJUXSFkrxUnMlQZelRLGW8uZdiqA1KCWovGei7VldaV6vVfCplZKsWV3aWaig3LbCIuRVBcpfsXKYhli6riMo7DtMaa081hrZXGods0xpZyADcnylx6Q+eGqNvSY1SoNbYI1VqBUkXjdGn5cboUJrZL6ul9rpU8vziG5yYa83ZtjZWzEAA2fNmJC16QMkAA&html=DwCwLgtgNgfAsAKEaApgQwCbwQAjz4CFMNHcMABwFoUBHAVwEsA3AXgHIBhAewDswU-KgBUAnhRTscAYz4D+HAQA8wAenDQA3DJBoATgGdiremABmVABzts+Agel7GFMDgN7prAEQB9HwAkAeQBlYT9VKEYAIwNVPXRpMAA6Cj1uDHpExj4kiEZeJIArAy8YYFUHJxdbfGBK51d3T18AkLCfCOjY+LREqgxuCBS0jKycvILi0vL66uR1dCxEZCj00RkoNAMDbzQKall+NHyUPVLEO2AMFhxGDG8UKDyDECo9ii8NrZ2vR+fX97TVTXZjYcqrDCibDzDSwRBAA&css=BYFwtgNgNAsAUAIwPYBMCeACA3vDeMBmSAdiALQDOAlgF4CmAXBgIwBsADgB4Dc8AvvHgA6MAEMqxMgGMSIccToAnbLnwoqFdhFFomBCHR6q8AdyooQwJswAMNgKS84+DMDpUA5qGt3HxjABWAK4UIFQEaNKydKRMUjEgSk4uohCeklSJYBRxCUn++oZk6op0UmEkcUgQQWDETgJwwhLsQSAqzvjsoijqxB5MQgBMAKylYMn4RKSUtIwsHEadpuaWTKM2XJN4YooeEmTIICBIYNbjDfBAA | |
open Fable.Import.JS | |
open Fable.Core.JsInterop | |
open Fable.Core | |
[<Import("equalArraysWith", "fable-library/Util.js")>] | |
let private equalArraysWith (x: obj) (y: obj) (cmp: obj -> obj -> bool): bool = | |
jsNative | |
[<Import("compareDates", "fable-library/Util.js")>] | |
let private compareDates (x: obj) (y: obj): int = | |
jsNative | |
[<Emit("$0 == $1")>] | |
let private jsEquals (x : obj) (y : obj) : bool = jsNative | |
[<Emit("$0 != $1")>] | |
let private jsNotEquals (x : obj) (y : obj) : bool = jsNative | |
let private sameType (x: obj) (y: obj) = | |
jsNotEquals y null && | |
obj.ReferenceEquals( | |
Object.getPrototypeOf(x)?constructor, | |
Object.getPrototypeOf(y)?constructor) | |
[<Emit("typeof $0")>] | |
let private jsTypeof (_ : obj) : string = jsNative | |
[<Emit("$0 instanceof Date")>] | |
let private isDate (_ : obj) : bool = jsNative | |
let inline private isArray (x: obj) = | |
Array.isArray x || ArrayBuffer.isView x | |
let private recordPrototype = | |
Object.getPrototypeOf({| marker = true |}) | |
let rec private isRecord (x: obj) = | |
if jsEquals x null then | |
false | |
else | |
let proto = Object.getPrototypeOf(x) | |
(obj.ReferenceEquals(recordPrototype, proto) | |
|| isRecord proto) | |
let rec private recordEquals (self: obj) (other: obj) = | |
if obj.ReferenceEquals(self, other) then | |
true | |
else if not (sameType self other) then | |
false | |
else | |
let thisNames = Object.keys(self) | |
let length = thisNames.Count | |
let mutable i = 0 | |
let mutable result = true | |
while i < length && result do | |
let thisName = thisNames.[i] | |
i <- i + 1 | |
let selfValue = self?(thisName) | |
let otherValue = other?(thisName) | |
if not (equals selfValue otherValue) then | |
result <- false | |
result | |
and equals (x: obj) (y: obj) = | |
if obj.ReferenceEquals(x, y) then | |
true | |
else if jsEquals x null then | |
jsEquals y null | |
else if jsEquals y null then | |
false | |
else if jsTypeof x = "function" then | |
// Functions are considered equals between each | |
// other so that dispatch can be passed freely | |
jsTypeof y = "function" | |
else if jsTypeof x <> "object" then | |
false | |
else if isRecord x then | |
// Use a special record comparer instead of the default | |
// one to use this equals deeply | |
isRecord y && recordEquals x y | |
else if jsTypeof x?Equals = "function" then | |
x?Equals(y) | |
else if isArray x then | |
isArray y && equalArraysWith x y equals | |
else if isDate x then | |
isDate y && (compareDates x y = 0) | |
else // TODO: Dates | |
false | |
type private A = { y: int } | |
type private B = { y: int } | |
let private x = {| y = 2 |} | |
let private y = {| y = 2 |} | |
printfn "%A" (isRecord x) | |
printfn "%A" (isRecord y) | |
printfn "%A" (isRecord { A.y = 5}) | |
console.log(Object.getPrototypeOf {| y = 5 |}) | |
console.log(Object.getPrototypeOf { A.y = 5}) | |
printfn "--" | |
printfn "true %A" (equals x {| y = 2 |}) | |
printfn "false %A" (equals x {| y = 3 |}) | |
printfn "false %A" (equals x { A.y = 2 }) | |
printfn "false %A" (equals { B.y = 2 } { A.y = 2 }) | |
printfn "true %A" (equals { A.y = 2 } { A.y = 2 }) | |
printfn "false %A" (equals x 3) | |
printfn "true %A" (equals 3 3) | |
printfn "false %A" (equals 2 3) | |
printfn "--" | |
let private f x = 1 | |
let private f2 x = 2 | |
printfn "true %A" (equals {| x = 5; y = f |} {| x = 5; y = f |}) | |
printfn "true %A" (equals {| x = 5; y = f |} {| x = 5; y = f2 |}) | |
printfn "false %A" (equals {| x = 5; y = f |} {| x = 6; y = f2 |}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment