Skip to content

Instantly share code, notes, and snippets.

@vbfox
Last active April 16, 2019 15:27
Show Gist options
  • Save vbfox/370bbb41cc4bb51d289f53dea7c71547 to your computer and use it in GitHub Desktop.
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
// 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