[m-users.] Using type constructors in predicate heads

Sean Charles (emacstheviking) objitsu at gmail.com
Sun Nov 7 20:50:16 AEDT 2021


Julien, 

An additional change I had to make, seeking explanation! I think I know why but just would like to fully understand… here is the predicate that is calling the do_gencall predicate, note that the type of Term is an snode...

:- pred translate_all_terms(renderer, lsnode, tcon, tcon).
:- mode translate_all_terms(renderer, in, in, out) is det.

translate_all_terms(_, [], !_T).

translate_all_terms(R, [ Term | Terms ], !T) :-
    TPos = snpos(Term),
    ( if Term = sexp(Spos, [ tk(Tpos,F) | Args ]) then
        (
            is_illegal_inst(F)
        ->
            syntax.error(TPos, top_level_form_required, !T)
        ;
            (
                bifmap(F, _Inst)
            ->
                % FELT function call
                syntax.error(TPos, msg("this is a felt call"), !T)
            ;
                do_gencall(0, R,
                    sexp(Spos, [tk(Tpos,F) | Args ]),  % <— the change!
                    !T)
		% it was: do_gencall(0, R, Term, !T),
            )
        )
    else
        syntax.error(TPos, expected_s_expression, !T)
    ),
    translate_all_terms(R, Terms, !T).

and for completeness:

:- pred do_gencall(int, renderer, snode, tcon, tcon).
:- mode do_gencall(in, renderer, in(sexp_ne), in, out) is det.
:- inst sexp_ne for snode/0 ---> sexp(ground, non_empty_list).

do_gencall(_L, R, sexp(_, [Functor|Args]), !T) :-
	:

I got a huge great compiler message compiler message which was, I think, trying to tell me that the type of Term was sexp(ground, ground), which thanks to your previous response I now fully understood! In order to remove the error message I had to work out that, in order to fully satisfy the constraint of an expected non empty list, that I had to explicitly construct the term again, in situ at the call site so that it was plan to the compiler that lo! here is a non empty list in the expected position…it compiled and the code runs again once more.

The error message was this:

translate.m:216: In clause for `translate_all_terms((translate.renderer), in,
translate.m:216:   in, out)':
translate.m:216:   mode error in conjunction. The next 3 error messages
translate.m:216:   indicate possible causes of this error.
translate.m:216:   
translate.m:205:   In clause for `translate_all_terms((translate.renderer), in,
translate.m:205:   in, out)':
translate.m:205:   in argument 3 of call to predicate `translate.do_gencall'/5:
translate.m:205:   mode error: variable `Term' has instantiatedness
translate.m:205:   `bound(sexp(ground, ground))',
translate.m:205:   expected instantiatedness was
translate.m:205:     named inst sexp_ne,
translate.m:205:     which expands to
translate.m:205:       bound(
translate.m:205:         sexp(
translate.m:205:           ground,
translate.m:205:           named inst list.non_empty_list,
translate.m:205:           which expands to
translate.m:205:             bound(
translate.m:205:               '[|]'(ground, ground)
translate.m:205:             )
translate.m:205:         )
translate.m:205:       ).

I think I understood it enough to figure out the solution, so thanks again for the enlightening responses.
I think this is one of the nicest language lists I’ve had the pleasure to be a member of!

Thanks,
Sean.



> On 7 Nov 2021, at 09:24, Julien Fischer <jfischer at opturion.com> wrote:
> 
> 
> Hi Sean,
> 
> On Sun, 7 Nov 2021, Sean Charles (emacstheviking) wrote:
> 
>> I made your suggested change, it works fine but… can I push it a
>> little further? I went back to the Mercury crash course page as it
>> mentioned non_empty_list, I found no references in the reference guide
>> or the library but plenty in the source code for my ROTD version… but
>> I am unsure of the syntax, if possible, of stating that the the list
>> of terms to the sexp() functor is guaranteed to be non empty because:
>>     ( if Term = sexp(_, [ tk(_,F) | _ ]) then
>> already established that fact prior to the call…but this leads me to
>> my final question: —should— I be doing this? I ask because
>> :- mode do_gencall(in, renderer, in(sexp), in, out) is det.
>> do_gencall(_L, R, sexp(_, [Functor|Args]), !T) :-
>> This obv. fails because the unification into head and tail could fail,
>> but if I declare it as semidet then obv. I have to check the call
>> further up the code, again I totally understand why but my question
>> then is, should I do this at all ? I have not used Haskell in a while
>> now, plumping for Mercury, but I was getting reasonably proficient at
>> the concept of `programming with types` and this feels similar. If I
>> instructed the compiler that the mode was something like
>> :- mode do_gencall(in, renderer, in(sexp-with-non-empty-args), in, out) is det.
>> then presumably the predicate could remain as `det`, everybody is
>> happy and my code feels more rigorous for it. I refer to the sample of
>> code in the file ‘./mercury-srcdist-20.06.1/browser/parse.m’ , lines
>> 305 to 307:
>> :- pred lexer_arg(list(char)::in(non_empty_list), list(token)::out) is det.
>> lexer_arg([Head | Tail], Toks) :-
>> This clearly shows to me that by using non_empty_list the compiler is
>> happy to let me deconstruct the list in the clause head with no
>> problems. I am not sure how to combine the mode you showed me with the
>> addition of the non empty constraint as well that’s all!
> 
> As a separate named inst:
> 
>   :- inst sexp_with_non_empty_args for snode/0
>       --->    sexp(ground, non_empty_list).
> 
>   :- mode do_gencall(in, renderer, in(sexp_with_non_empty_args),
>      in, out) is det.
> 
> or inline:
> 
>   :- mode do_gencall(in, renderer, in(bound(sexp(ground, non_empty_list))),
>      in, out) is det.
> 
> Julien

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mercurylang.org/archives/users/attachments/20211107/3fbb1a00/attachment.html>


More information about the users mailing list