<html><head><meta http-equiv="content-type" content="text/html; charset=us-ascii"></head><body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;">OK, I have fixed it all and made it compile and amazingly it works, here's what I had to do, a great learning experience this evening for sure.<div><br></div><div><div><font face="CascadiaMono-Regular">:- pred collisions_between2(</font></div><div><font face="CascadiaMono-Regular"> coll_type::in, % Check</font></div><div><font face="CascadiaMono-Regular"> list(S)::in, % Shots0</font></div><div><font face="CascadiaMono-Regular"> list(T)::in, % Targets0</font></div><div><font face="CascadiaMono-Regular"> list(S)::out, % Shots</font></div><div><font face="CascadiaMono-Regular"> list(T)::out % Targets</font></div><div><font face="CascadiaMono-Regular">) is det <= ( hittable(S), hittable(T) ).</font></div><div><font face="CascadiaMono-Regular"><br></font></div><div><font face="CascadiaMono-Regular">%</font></div><div><font face="CascadiaMono-Regular">% ideal: two list of things, none with hit flags set, actuall, indifferent.</font></div><div><font face="CascadiaMono-Regular">% on exit: two NEW list of list, some with hit flags set, some without.</font></div><div><font face="CascadiaMono-Regular">%</font></div><div><font face="CascadiaMono-Regular">collisions_between2(Check, Shots0, Targets0, Shots, Targets) :-</font></div><div><font face="CascadiaMono-Regular"> list.foldl2(</font></div><div><font face="CascadiaMono-Regular"> outer(Check, Targets0),</font></div><div><font face="CascadiaMono-Regular"> Shots0,</font></div><div><font face="CascadiaMono-Regular"> set.init:set(S), Shots1,</font></div><div><font face="CascadiaMono-Regular"> set.init:set(T), Targets1</font></div><div><font face="CascadiaMono-Regular"> ),</font></div><div><font face="CascadiaMono-Regular"> Shots = set.to_sorted_list(Shots1),</font></div><div><font face="CascadiaMono-Regular"> Targets = set.to_sorted_list(Targets1),</font></div><div><font face="CascadiaMono-Regular"> trace [io(!IO)] (</font></div><div><font face="CascadiaMono-Regular"> io.format("COLL2: Shots: %i\n", [i(list.length(Shots))], !IO),</font></div><div><font face="CascadiaMono-Regular"> io.format("COLL2: Targs: %i\n", [i(list.length(Targets))], !IO)</font></div><div><font face="CascadiaMono-Regular"> ).</font></div><div><font face="CascadiaMono-Regular"><br></font></div><div><font face="CascadiaMono-Regular">:- pred outer(</font></div><div><font face="CascadiaMono-Regular"> coll_type::in, % Check</font></div><div><font face="CascadiaMono-Regular"> list(T)::in, % Targets (Targets0 from caller)</font></div><div><font face="CascadiaMono-Regular"> S::in, % Shot</font></div><div><font face="CascadiaMono-Regular"> set(S)::in, set(S)::out, % !L1acc</font></div><div><font face="CascadiaMono-Regular"> set(T)::in, set(T)::out % !L2acc</font></div><div><font face="CascadiaMono-Regular">) is det <= ( hittable(S), hittable(T) ).</font></div><div><font face="CascadiaMono-Regular"><br></font></div><div><font face="CascadiaMono-Regular">outer(Check, Targets, Shot, !L1acc, !L2acc) :-</font></div><div><font face="CascadiaMono-Regular"> list.foldl2(</font></div><div><font face="CascadiaMono-Regular"> inner(Check, Shot),</font></div><div><font face="CascadiaMono-Regular"> Targets,</font></div><div><font face="CascadiaMono-Regular"> !L1acc,</font></div><div><font face="CascadiaMono-Regular"> !L2acc</font></div><div><font face="CascadiaMono-Regular"> ).</font></div><div><font face="CascadiaMono-Regular"><br></font></div><div><font face="CascadiaMono-Regular">:- pred inner(</font></div><div><font face="CascadiaMono-Regular"> coll_type::in, % Check</font></div><div><font face="CascadiaMono-Regular"> S::in, % Shot</font></div><div><font face="CascadiaMono-Regular"> T::in, % Target</font></div><div><font face="CascadiaMono-Regular"> set(S)::in, set(S)::out, % L1acc</font></div><div><font face="CascadiaMono-Regular"> set(T)::in, set(T)::out % !L2acc</font></div><div><font face="CascadiaMono-Regular">) is det <= ( hittable(S), hittable(T) ).</font></div><div><font face="CascadiaMono-Regular"><br></font></div><div><font face="CascadiaMono-Regular">inner(Check, Shot, Target, !L1acc, !L2acc) :-</font></div><div><font face="CascadiaMono-Regular"> ( if did_collide(Check, Shot, Target) then</font></div><div><font face="CascadiaMono-Regular"> set_hit(Shot, Shot1),</font></div><div><font face="CascadiaMono-Regular"> set_hit(Target, Target1),</font></div><div><font face="CascadiaMono-Regular"> set.insert(Shot1, !L1acc),</font></div><div><font face="CascadiaMono-Regular"> set.insert(Target1, !L2acc)</font></div><div><font face="CascadiaMono-Regular"> else</font></div><div><font face="CascadiaMono-Regular"> set.insert(Shot, !L1acc),</font></div><div><font face="CascadiaMono-Regular"> set.insert(Target, !L2acc)</font></div><div><font face="CascadiaMono-Regular"> ).</font></div><div><br></div><div>The only mystery is that I didn't have to provide the `equality` predicate as described in "8 User-defined equality and comparison" of the referece.</div><div>So what did mercury do for me that I didn't have to do.</div><div><br></div><div>Would it be more efficient if, for each of my DU types that implements the hittable typeclass also proved an implementation of `where equality...` and returned the simple internal integer index assigned to it, guaranteed unique for the entire game session?</div><div><br></div><div><br></div><div>Thanks for everybody helping me out.</div><div>Sean.</div><div><br></div><div><br><blockquote type="cite"><div>On 11 Oct 2023, at 22:16, Sean Charles (emacstheviking) <objitsu@gmail.com> wrote:</div><br class="Apple-interchange-newline"><div><meta http-equiv="content-type" content="text/html; charset=us-ascii"><div style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div>collisions_between2(Check, Shots0, Targets0, Shots, Targets) :-</div><div> Outer = (pred(</div><div> Shot::in,</div><div> !.S::in, !:S::out,</div><div> !.T::in, !:T::out</div><div><b> ) is det <= (hittable(S), hittable(T)) :-</b></div><div> Inner = (pred(</div><div> Target::in,</div><div> !.S::in, !:S::out,</div><div> !.T::in, !:T::out</div><div><b> ) is det <= (hittable(S), hittable(T)) :-</b></div><div> ( if did_collide(Check, Shot, Target)</div><div> then</div><div> set_hit(Shot, Shot1),</div><div> set_hit(Target, Target1),</div><div> set.insert_new(Shot1, !S),</div><div> set.insert_new(Target1, !T)</div><div> else</div><div> set.insert_new(Shot, !S),</div><div> set.insert_new(Target, !T)</div><div> )</div><div> ),</div><div> list.foldl2(Inner, Targets0, !S, !T)</div><div> ),</div><div> list.foldl2(</div><div> Outer, Shots0,</div><div><b> set.init:set(S), ShotsX,</b></div><div><b> set.init:set(T), TargetsX</b></div><div> ),</div><div> trace [io(!IO)] (</div><div> io.format("COLL2: Shots: %i\n", [i(list.length(Shots))], !IO),</div><div> io.format("COLL2: Targs: %i\n", [i(list.length(Targets))], !IO)</div><div> ).</div><div><br></div><div>Errors:</div><div><br></div><div><div>level_ufo.m:809: Error: the clause head part of a lambda expression should have</div><div>level_ufo.m:809: one of the following forms: `pred(<args>) is <determinism>'</div><div>level_ufo.m:809: `any_pred(<args>) is <determinism>'</div><div>level_ufo.m:809: `func(<args>) = <retarg> is <determinism>'</div><div>level_ufo.m:809: `any_func(<args>) = <retarg> is <determinism>'</div><div>level_ufo.m:809: `func(<args>) = <retarg>'</div><div>level_ufo.m:809: `any_func(<args>) = <retarg>',</div><div>level_ufo.m:809: or one of those forms preceded by either `semipure' or</div><div>level_ufo.m:809: `impure'.</div></div><div><br></div><div>It doesn't seem like it is acceptable on a lambda expression, so will I have to break this code out into discrete predicates?</div><div><br></div><div><br></div><div><br><blockquote type="cite"><div>On 10 Oct 2023, at 23:42, Zoltan Somogyi <zoltan.somogyi@runbox.com> wrote:</div><br class="Apple-interchange-newline"><div><div><br>On 2023-10-11 09:19 +11:00 AEDT, "Sean Charles (emacstheviking)" <objitsu@gmail.com> wrote:<br><blockquote type="cite">Then I did what I thought would work:<br><br>:- type l1_set(T) == set(hittable(T)) <= hittable(T).<br></blockquote><br>If what you are after is "the type of a set of things where each thing is hittable",<br>what you need to do is to simply use "set(T)" where you want this, *and*<br>add the typeclass constraint "<= hittable(T)" to the declarations of the<br>predicates and functions where such an argument appears. For an example,<br>have a look at e.g. sparse_bitset.m in the standard library.<br><br><blockquote type="cite">And here is the actual code where I am trying to use it, I am operating on the assumption<br>that by default Mercury has some way of creating a unique hash for each object<br></blockquote><br>That assumption is incorrect. The int.m, uint.m and string.m modules<br>of the standard library define hash functions, but for other types,<br>providing a hash function is up to you. And while there exist algorithms<br>for creating perfect hash functions (i.e. hash functions that don't generate<br>any collisions on a given set of input values),<br><br>- they guarantee the absence of collisions *only* for that set of values,<br>- they require the values of that set to be specified in advance,<br>- and even then they fail to generate a hash function for some sets.<br><br>Even cryptographically secure hash functions can have collisions.<br>The pigeon-hole principle guarantees this for any hash function<br>that generates a hash value of a fixed size for inputs of unbounded size.<br><br><blockquote type="cite"> Ah.. it is section 3.8 of the online page https://mercury-in.space/crash.html#orga13c54a<br></blockquote><br>That section does not talk about hashing.<br><br>Zoltan.</div></div></blockquote></div><br></div></div></blockquote></div><br></div></body></html>