<div dir="auto">As far as I'm concerned, nonreflexive instances are not supported by `containers` at all. If your == isn't reflexive, you just need to assume that anything with an Eq constraint might behave arbitrarily badly.</div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Fri, Jun 11, 2021, 10:27 AM Simon Jakobi via Haskell-Cafe <<a href="mailto:haskell-cafe@haskell.org">haskell-cafe@haskell.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Thanks for the feedback everyone! :)<br>
<br>
The gist I get is that using pointer equality is not free, but it can<br>
make sense when<br>
<br>
1. two objects are particularly likely to be the same;<br>
2. establishing equality by other means (e.g. structural equality) is<br>
particularly expensive<br>
<br>
The usecases I now have in mind are:<br>
<br>
* Lookups in unordered-containers: Since keys are only ==-d when their<br>
hashes are equal, it seems that the likelihood that they are in fact<br>
the same object should be fairly good. I think we can ignore the issue<br>
of irreflexive instances here, because the lookup logic already<br>
requires reflexivity.<br>
<br>
* The Eq instances of containers' Set and IntSet types and of HashSet<br>
from unordered-containers. These instances seem particularly<br>
expensive, and Set and HashSet already require reflexivity. I don't<br>
think we can apply the same optimizations to the Eq instances of the<br>
various Map types, because we might run into irreflexive values there.<br>
<br>
* Eq for lazy ByteStrings – another expensive instance. The instance<br>
for strict ByteStrings already makes use of pointer equality.<br>
<br>
Cheers,<br>
Simon<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
Am Di., 8. Juni 2021 um 18:51 Uhr schrieb Sebastiaan Joosten<br>
<<a href="mailto:sjcjoosten%2Bhaskell@gmail.com" target="_blank" rel="noreferrer">sjcjoosten+haskell@gmail.com</a>>:<br>
><br>
> The containers library uses this trick:<br>
> <a href="https://github.com/haskell/containers/blob/30ccbaa201043109bf1ee905c66ccd0dbe24422f/containers/src/Utils/Containers/Internal/PtrEquality.hs" rel="noreferrer noreferrer" target="_blank">https://github.com/haskell/containers/blob/30ccbaa201043109bf1ee905c66ccd0dbe24422f/containers/src/Utils/Containers/Internal/PtrEquality.hs</a><br>
> It mentions the useful hint to evaluate the arguments to WHNF before calling PtrEquality.<br>
> The function ptrEq is used here (for instance):<br>
> <a href="https://github.com/haskell/containers/blob/30ccbaa201043109bf1ee905c66ccd0dbe24422f/containers/src/Data/Set/Internal.hs#L532" rel="noreferrer noreferrer" target="_blank">https://github.com/haskell/containers/blob/30ccbaa201043109bf1ee905c66ccd0dbe24422f/containers/src/Data/Set/Internal.hs#L532</a><br>
> The places where ptrEq is used in that file, its purpose seems to be to reduce memory by reusing existing data-structures, which I suppose also helps with performance.<br>
> Surprisingly enough (at least to me) ptrEq is not used in the Eq instance there:<br>
> <a href="https://github.com/haskell/containers/blob/30ccbaa201043109bf1ee905c66ccd0dbe24422f/containers/src/Data/Set/Internal.hs#L1141" rel="noreferrer noreferrer" target="_blank">https://github.com/haskell/containers/blob/30ccbaa201043109bf1ee905c66ccd0dbe24422f/containers/src/Data/Set/Internal.hs#L1141</a><br>
><br>
> Outside of GHC, there are some (pure) languages that extensively make use of this principle and it's too cool not to mention:<br>
> The programming language Elm does this in its generated code (at least when generating JavaScript): <a href="https://github.com/elm/compiler/" rel="noreferrer noreferrer" target="_blank">https://github.com/elm/compiler/</a><br>
> The theorem proving environment ACL2 uses this principle for memoizing functions, fast 'Map's ('dictionaries' in python lingo, 'alist' or association-list in ACL2 lingo), as well as fast equality. As a LISP dialect, all data-structures are pairs (called CONS). In ACL2, the function 'HONS' (hashed CONS) will construct a pair if it does not already exist, and otherwise it returns a pointer to the already existing object. The point of using HONS in ACL2 is to only perform pointer comparison, without needing to do any other equality check.<br>
> General background information: <a href="https://www.cs.utexas.edu/~ragerdl/acl2-manual/index.html?topic=ACL2____HONS-AND-MEMOIZATION" rel="noreferrer noreferrer" target="_blank">https://www.cs.utexas.edu/~ragerdl/acl2-manual/index.html?topic=ACL2____HONS-AND-MEMOIZATION</a><br>
> The equality test: <a href="https://www.cs.utexas.edu/users/moore/acl2/manuals/current/manual/index-seo.php/ACL2____HONS-EQUAL" rel="noreferrer noreferrer" target="_blank">https://www.cs.utexas.edu/users/moore/acl2/manuals/current/manual/index-seo.php/ACL2____HONS-EQUAL</a><br>
> And there is of course a function to create a 'normed object': <a href="https://www.cs.utexas.edu/users/moore/acl2/manuals/current/manual/index-seo.php/ACL2____HONS-COPY" rel="noreferrer noreferrer" target="_blank">https://www.cs.utexas.edu/users/moore/acl2/manuals/current/manual/index-seo.php/ACL2____HONS-COPY</a><br>
> Note that the ACL2 approach only works because it is supported by the run time system (the implementation needs to access 'all data in memory') so it won't work in Haskell (assuming you're not writing your own RTS).<br>
><br>
> Hope this helps.<br>
><br>
> On Tue, Jun 8, 2021 at 10:47 AM Joachim Durchholz <<a href="mailto:jo@durchholz.org" target="_blank" rel="noreferrer">jo@durchholz.org</a>> wrote:<br>
>><br>
>> Am 08.06.21 um 16:25 schrieb Simon Jakobi via Haskell-Cafe:<br>
>> > Hi everyone!<br>
>> ><br>
>> > In <a href="https://github.com/haskell-unordered-containers/unordered-containers/issues/77" rel="noreferrer noreferrer" target="_blank">https://github.com/haskell-unordered-containers/unordered-containers/issues/77</a><br>
>> > we're wondering whether certain Eq instances, for example record types<br>
>> > or strings, could be optimized by including a pointer equality check<br>
>> > that detects when an object is compared with itself.<br>
>><br>
>> You have to be aware that the pointer comparison itself does not come<br>
>> for free. Execution prediction means that the "happy path" may be so<br>
>> rare it's not loaded into the CPU cache and you might end with a slower<br>
>> system - the case is somewhat pathological but not so rare that you can<br>
>> just assume that it will not happen to you.<br>
>> A lot also depends on whether the data to be compared needs to be loaded<br>
>> anyway. If yes, the pointer comparison won't give you any gains, it will<br>
>> be just one instruction more to execute, creating more execution unit<br>
>> contention inside the CPU. If no, then obviously the pointer comparison<br>
>> will help.<br>
>><br>
>> In the end, you need to benchmark to see if it helps you.<br>
>> And you cannot usefully benchmark unless you have also nailed down all<br>
>> performance-relevant compiler and runtime options, which you do only if<br>
>> you have exhausted all other optimization possibilities.<br>
>><br>
>> IOW if it complicates your code, don't do it - unless you are already<br>
>> long past the point where code reusability has taken a back seat to raw<br>
>> optimization.<br>
>><br>
>> Regards,<br>
>> Jo<br>
>> _______________________________________________<br>
>> Haskell-Cafe mailing list<br>
>> To (un)subscribe, modify options or view archives go to:<br>
>> <a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
>> Only members subscribed via the mailman list are allowed to post.<br>
><br>
> _______________________________________________<br>
> Haskell-Cafe mailing list<br>
> To (un)subscribe, modify options or view archives go to:<br>
> <a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
> Only members subscribed via the mailman list are allowed to post.<br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
To (un)subscribe, modify options or view archives go to:<br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
Only members subscribed via the mailman list are allowed to post.</blockquote></div>