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

Sean Charles (emacstheviking) objitsu at gmail.com
Sun Nov 7 19:43:39 AEDT 2021


Hi Julien,
Thanks for that. I knew in the back of my mind I had read something about using inst. I thrashed around for about an hour and in the end I just declared a new type! This answer though I will read until I get it and then apply it to my code.

I am using:
{7:40}~/Documents/code/mercury/f2:ast-start ✗ ➭ mmc -v
Mercury Compiler, version 20.06.1, on x86_64-apple-darwin19.6.0
Copyright (C) 1993-2012 The University of Melbourne
Copyright (C) 2013-2020 The Mercury team
Usage: mmc [<options>] <arguments>
Use `mmc --help' for more information.

In section 3.2.4 the words “experimental” and “subject to change” were enough for me , 

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!

This is currently at the edges of both my knowledge and comfort with Mercury , I am hoping to learn some more from you guys.

Thanks,
Sean.









Thanks again,
Sean



> On 7 Nov 2021, at 04:11, Julien Fischer <jfischer at opturion.com> wrote:
> 
> 
> Hi Sean,
> 
> On Sat, 6 Nov 2021, Sean Charles (emacstheviking) wrote:
> 
>> Is it possible / allowed to write a predicate declaration to
>> explicitly mention a single type from a set of types? I seem to have a
>> pattern cropping up again and again lately, here is my current
>> situation. I have a node type:
>> :- type snode
>>     --->    sexp(location, list(snode))
>>     ;       list(location, list(snode))
>>     ;       map(location, list(snode))
>>     ;       tk(location,string)
>>     ;       kw(location, string)
>>     ;       s1(location,string)
>>     ;       s2(location,string)
>>     .
>> In my code, I have performed some pre-checks on a term 
>>     ( if Term = sexp(_, [tk(_, F)|_]) then
>> such that when I call the predicate to handle it, I —know— that it can
>> only be the one containing an s-expression, but it seems that I am
>> forced to define the predicate I call as the containing `snode` type,
>> I guess what I am saying is is it possible to change this:
>> :- pred do_gencall(int, renderer, snode, tcon, tcon).
>> :- mode do_gencall(in, renderer, in, in, out) is det.
>> do_gencall(L, R, Term, !T) :-
>> to this in some way?
>> :- pred do_gencall(int, renderer, snode:sexp, tcon, tcon).
>> :- mode do_gencall(in, renderer, in, in, out) is det.
>> do_gencall(L, R, Term, !T) :-
> 
> Yes, use inst subtyping.
> 
>    :- pred do_gencall(int, renderer, snode, tcon, tcon).
>    :- mode do_gencall(in, renderer, in(sexp(ground, ground)), in, out) is det.
> 
> It's a little cleaner to do:
> 
>   :- inst sexp for snode/0
>      --->  sexp(ground, ground).
> 
>   :- pred do_gencall(int, renderer, snode, tcon, tcon).
>   :- mode do_gencall(in, renderer, in(sexp), in, out) is det.
> 
> If you're using a recent ROTD you could alternatively use subtypes
> to achieve the same thing:
> <http://mercurylang.org/information/doc-latest/mercury_ref/Subtypes.html#Subtypes>
> 
> Julien.

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


More information about the users mailing list