[m-users.] How to declare a set of typeclasses?
Sean Charles (emacstheviking)
objitsu at gmail.com
Thu Oct 12 09:10:35 AEDT 2023
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.
:- pred collisions_between2(
coll_type::in, % Check
list(S)::in, % Shots0
list(T)::in, % Targets0
list(S)::out, % Shots
list(T)::out % Targets
) is det <= ( hittable(S), hittable(T) ).
%
% ideal: two list of things, none with hit flags set, actuall, indifferent.
% on exit: two NEW list of list, some with hit flags set, some without.
%
collisions_between2(Check, Shots0, Targets0, Shots, Targets) :-
list.foldl2(
outer(Check, Targets0),
Shots0,
set.init:set(S), Shots1,
set.init:set(T), Targets1
),
Shots = set.to_sorted_list(Shots1),
Targets = set.to_sorted_list(Targets1),
trace [io(!IO)] (
io.format("COLL2: Shots: %i\n", [i(list.length(Shots))], !IO),
io.format("COLL2: Targs: %i\n", [i(list.length(Targets))], !IO)
).
:- pred outer(
coll_type::in, % Check
list(T)::in, % Targets (Targets0 from caller)
S::in, % Shot
set(S)::in, set(S)::out, % !L1acc
set(T)::in, set(T)::out % !L2acc
) is det <= ( hittable(S), hittable(T) ).
outer(Check, Targets, Shot, !L1acc, !L2acc) :-
list.foldl2(
inner(Check, Shot),
Targets,
!L1acc,
!L2acc
).
:- pred inner(
coll_type::in, % Check
S::in, % Shot
T::in, % Target
set(S)::in, set(S)::out, % L1acc
set(T)::in, set(T)::out % !L2acc
) is det <= ( hittable(S), hittable(T) ).
inner(Check, Shot, Target, !L1acc, !L2acc) :-
( if did_collide(Check, Shot, Target) then
set_hit(Shot, Shot1),
set_hit(Target, Target1),
set.insert(Shot1, !L1acc),
set.insert(Target1, !L2acc)
else
set.insert(Shot, !L1acc),
set.insert(Target, !L2acc)
).
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.
So what did mercury do for me that I didn't have to do.
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?
Thanks for everybody helping me out.
Sean.
> On 11 Oct 2023, at 22:16, Sean Charles (emacstheviking) <objitsu at gmail.com> wrote:
>
> collisions_between2(Check, Shots0, Targets0, Shots, Targets) :-
> Outer = (pred(
> Shot::in,
> !.S::in, !:S::out,
> !.T::in, !:T::out
> ) is det <= (hittable(S), hittable(T)) :-
> Inner = (pred(
> Target::in,
> !.S::in, !:S::out,
> !.T::in, !:T::out
> ) is det <= (hittable(S), hittable(T)) :-
> ( if did_collide(Check, Shot, Target)
> then
> set_hit(Shot, Shot1),
> set_hit(Target, Target1),
> set.insert_new(Shot1, !S),
> set.insert_new(Target1, !T)
> else
> set.insert_new(Shot, !S),
> set.insert_new(Target, !T)
> )
> ),
> list.foldl2(Inner, Targets0, !S, !T)
> ),
> list.foldl2(
> Outer, Shots0,
> set.init:set(S), ShotsX,
> set.init:set(T), TargetsX
> ),
> trace [io(!IO)] (
> io.format("COLL2: Shots: %i\n", [i(list.length(Shots))], !IO),
> io.format("COLL2: Targs: %i\n", [i(list.length(Targets))], !IO)
> ).
>
> Errors:
>
> level_ufo.m:809: Error: the clause head part of a lambda expression should have
> level_ufo.m:809: one of the following forms: `pred(<args>) is <determinism>'
> level_ufo.m:809: `any_pred(<args>) is <determinism>'
> level_ufo.m:809: `func(<args>) = <retarg> is <determinism>'
> level_ufo.m:809: `any_func(<args>) = <retarg> is <determinism>'
> level_ufo.m:809: `func(<args>) = <retarg>'
> level_ufo.m:809: `any_func(<args>) = <retarg>',
> level_ufo.m:809: or one of those forms preceded by either `semipure' or
> level_ufo.m:809: `impure'.
>
> It doesn't seem like it is acceptable on a lambda expression, so will I have to break this code out into discrete predicates?
>
>
>
>> On 10 Oct 2023, at 23:42, Zoltan Somogyi <zoltan.somogyi at runbox.com> wrote:
>>
>>
>> On 2023-10-11 09:19 +11:00 AEDT, "Sean Charles (emacstheviking)" <objitsu at gmail.com> wrote:
>>> Then I did what I thought would work:
>>>
>>> :- type l1_set(T) == set(hittable(T)) <= hittable(T).
>>
>> If what you are after is "the type of a set of things where each thing is hittable",
>> what you need to do is to simply use "set(T)" where you want this, *and*
>> add the typeclass constraint "<= hittable(T)" to the declarations of the
>> predicates and functions where such an argument appears. For an example,
>> have a look at e.g. sparse_bitset.m in the standard library.
>>
>>> And here is the actual code where I am trying to use it, I am operating on the assumption
>>> that by default Mercury has some way of creating a unique hash for each object
>>
>> That assumption is incorrect. The int.m, uint.m and string.m modules
>> of the standard library define hash functions, but for other types,
>> providing a hash function is up to you. And while there exist algorithms
>> for creating perfect hash functions (i.e. hash functions that don't generate
>> any collisions on a given set of input values),
>>
>> - they guarantee the absence of collisions *only* for that set of values,
>> - they require the values of that set to be specified in advance,
>> - and even then they fail to generate a hash function for some sets.
>>
>> Even cryptographically secure hash functions can have collisions.
>> The pigeon-hole principle guarantees this for any hash function
>> that generates a hash value of a fixed size for inputs of unbounded size.
>>
>>> Ah.. it is section 3.8 of the online page https://mercury-in.space/crash.html#orga13c54a
>>
>> That section does not talk about hashing.
>>
>> Zoltan.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurylang.org/archives/users/attachments/20231011/ac2bae32/attachment.html>
More information about the users
mailing list