[VPM] FYI: Muldis D code example, 2008 April 30 edition

Darren Duncan darren at darrenduncan.net
Thu May 1 01:13:34 PDT 2008


All,

This message is a follow-up both to my April 28th post of subject "ANNOUNCE 
- Muldis D v0.27.0 released", wherein I promised this message would soon 
follow, and also follows up a few other posts over the past year where I 
gave some pseudo-code examples.

At the end of this email is an example program written in Muldis D, which 
you can peruse to get familiar with what the language is like than just 
descriptions would do.

The example program will create a temporary depot/database, install a 
stored procedure in it, and invoke that stored procedure.  The stored 
procedure will prompt the user to enter details for 3 people, specifically 
their names and addresses, which it will store in a relvar/table.  It will 
then prompt the user to enter a person's name to search for, look for a 
matching person's details in the relvar/table, and then inform the user of 
that person's address.  Note that for brevity this example program is naive 
does not check that the search name actually matched 1 person, and simply 
tries to use the result, meaning it will die if that expectation isn't met; 
a real program would do more testing.

The program is written in the PTMD_Tiny dialect of Muldis D, which is 
designed to exactly match the system catalog in structure.  The majority of 
it, the stored procedure definition, consists of a single tuple/record for 
a catalog relvar/table, and some attributes/fields of that tuple/record 
have collection-typed values, several levels deep.  This Muldis D code 
should resemble the AST you get after parsing a typical language's code and 
so is fairly verbose.  Though verbose, it should work well in a situation 
where such code is mainly being generated or parsed or modified by a 
program, though doing it by hand should be tolerable.  The dialect is 
designed to be parseable with a tiny grammar, which is where its name comes 
from.  Muldis D is homoiconic, meaning Muldis D code fundamentally is a low 
level Muldis D data type, and you do all coding in it by manipulating data.

I assume that other Muldis D dialects will come about later where coding in 
it is a lot less verbose, at the cost of the grammar being more 
complicated, and code will translate between dialects.  Or alternately the 
Tiny dialect may just be used as an intermediate language for a programming 
environment that, say, takes some specialized DWIM language as input, and 
by way of the intermediate, generate SQL for any SQL DBMS to do the work.

So if there are any complaints about verbosity, I can probably do more to 
get that down in these dialects, but after a point it would probably be 
better to use some translation layer and write to that instead.

Now the PTMD_Tiny dialect happens to be well handled by syntax colorers for 
the Perl language, but it isn't Perl.  If you are a Perl programmer, you 
would probably be more interested in the HDMD_Perl_Tiny dialect, which 
looks very much like PTMD_Tiny, but consists of actual Perl arrays of 
arrays.  In fact, to translate from what you see below to the Perl version, 
basically just do this:

   - any "Foo:'bar':'baz'" gets changed to "[ 'Foo', 'bar', 'baz' ]"
   - any "\q" gets changed to "\'", or use alternate string quoting 
characters for string literals
   - for payloads of Relation and Set, change the delimiters to "[]" from 
"{}" since Perl 5 doesn't have set syntax so use array syntax instead
   - the framing code, the 'boot_call' etc need to be replaced with API 
calls to some Muldis D implementing Perl module such as Muldis Rosetta
   - for a further guide, just compare the docs for the 2 dialects, ad all 
the code examples directly correspond

Of course you don't have to use Perl, you could use some other host 
language instead as is your preference, as the structures map to any decent 
language easily enough.  Both functional and imperative languages should 
work with it.

Now the program example you see below is complete, with all framing code 
needed to compile the plain text dialect, probably.

In the near future, I'll follow with another example email that just shows 
snippits rather than a complete program, and the snippits can focus on 
particular tasks such as doing joins or unions or defining database schemas 
etc.

On another note, considering my OSCON talk is July 23, I've set myself up 
with a hard deadline of July 1, and a soft deadline of June 1, to have an 
actual working implementation of the language.  The only main prerequisite 
to making that is defining how to declare data types and schemas in the 
language, but that should be done in a few days I expect.

-- Darren Duncan

--------------

Muldis_D:'http://muldis.com':'0.28.0':'PTMD_Tiny':{};

boot_call:'sys.std.Core.Cat.create_temp_empty_depot':{
   'mount_name' => 'app',
};

boot_call:'sys.std.Core.Cat.create_depot_procedure':{
   'depot' => 'app',
   'parent' => Cat.DeclNameChain:'.',
   'name' => 'main',
   'comment' => Cat.Comment:'This is the program\qs main procedure.',
   'head' => Tuple:{},
   'body' => Tuple:{
     'main_body' => Tuple:{
       'vars' => Relation:[ 'name', 'type', ]:{
         [ 'msg_gather_name', Cat.NameChain:'sys.std.Core.Type.Text', ],
         [ 'msg_gather_addr', Cat.NameChain:'sys.std.Core.Type.Text', ],
         [ 'msg_search_name', Cat.NameChain:'sys.std.Core.Type.Text', ],
         [ 'msg_result_addr', Cat.NameChain:'sys.std.Core.Type.Text', ],
         [ 'people', Cat.NameChain:'sys.std.Core.Type.Relation', ],
         [ 'person_name', Cat.NameChain:'sys.std.Core.Type.Text', ],
         [ 'person_addr', Cat.NameChain:'sys.std.Core.Type.Text', ],
       },
       'stmts' => Seq:[
         Tuple:{
           'procedure' => Cat.NameChain:'inn.init_vars',
           'upd_args' => Relation:[ 'name', 'expr', ]:{
             [ 'msg_gather_name', Cat.NameChain:'lex.msg_gather_name', ],
             [ 'msg_gather_addr', Cat.NameChain:'lex.msg_gather_addr', ],
             [ 'msg_search_name', Cat.NameChain:'lex.msg_search_name', ],
             [ 'msg_result_addr', Cat.NameChain:'lex.msg_result_addr', ],
             [ 'people', Cat.NameChain:'lex.people', ],
           },
         },
         Tuple:{
           'procedure' => Cat.NameChain:'inn.gather_person',
           'upd_args' => Relation:[ 'name', 'expr', ]:{
             [ 'people', Cat.NameChain:'lex.people', ],
           },
           'ro_args' => Relation:[ 'name', 'expr', ]:{
             [ 'msg_gather_name', Cat.NameChain:'lex.msg_gather_name', ],
             [ 'msg_gather_addr', Cat.NameChain:'lex.msg_gather_addr', ],
           },
         },
         Tuple:{
           'procedure' => Cat.NameChain:'inn.gather_person',
           'upd_args' => Relation:[ 'name', 'expr', ]:{
             [ 'people', Cat.NameChain:'lex.people', ],
           },
           'ro_args' => Relation:[ 'name', 'expr', ]:{
             [ 'msg_gather_name', Cat.NameChain:'lex.msg_gather_name', ],
             [ 'msg_gather_addr', Cat.NameChain:'lex.msg_gather_addr', ],
           },
         },
         Tuple:{
           'procedure' => Cat.NameChain:'inn.gather_person',
           'upd_args' => Relation:[ 'name', 'expr', ]:{
             [ 'people', Cat.NameChain:'lex.people', ],
           },
           'ro_args' => Relation:[ 'name', 'expr', ]:{
             [ 'msg_gather_name', Cat.NameChain:'lex.msg_gather_name', ],
             [ 'msg_gather_addr', Cat.NameChain:'lex.msg_gather_addr', ],
           },
         },
         Tuple:{
           'procedure' => Cat.NameChain:'sys.std.Core.STDIO.prompt_Text_line',
           'upd_args' => Relation:[ 'name', 'expr', ]:{
             [ 'target', Cat.NameChain:'lex.person_name', ],
           },
           'ro_args' => Relation:[ 'name', 'expr', ]:{
             [ 'prompt', Cat.NameChain:'lex.msg_search_name', ],
           },
         },
         Tuple:{
           'procedure' => Cat.NameChain:'inn.search_for_address',
           'upd_args' => Relation:[ 'name', 'expr', ]:{
             [ 'person_addr', Cat.NameChain:'lex.person_addr', ],
           },
           'ro_args' => Relation:[ 'name', 'expr', ]:{
             [ 'people', Cat.NameChain:'lex.people', ],
             [ 'person_name', Cat.NameChain:'lex.person_name', ],
           },
         },
         Tuple:{
           'procedure' => Cat.NameChain:'sys.std.Core.STDIO.write_Text',
           'ro_args' => Relation:[ 'name', 'expr', ]:{
             [ 'v', Cat.NameChain:'lex.msg_result_addr', ],
           },
         },
         Tuple:{
           'procedure' => Cat.NameChain:'sys.std.Core.STDIO.write_Text_line',
           'ro_args' => Relation:[ 'name', 'expr', ]:{
             [ 'v', Cat.NameChain:'lex.person_addr', ],
           },
         },
       ],
     },
     'inner_procs' => Relation:{

       {
         'name' => 'gather_person',
         'comment' => Cat.Comment:'Gathers person info from user.',
         'head' => Tuple:{
           'upd_params' => Relation:[ 'name', 'type', ]:{
             [ 'people', Cat.NameChain:'sys.std.Core.Type.Relation', ],
           },
           'ro_params' => Relation:[ 'name', 'type', ]:{
             [ 'msg_gather_name', Cat.NameChain:'sys.std.Core.Type.Text', ],
             [ 'msg_gather_addr', Cat.NameChain:'sys.std.Core.Type.Text', ],
           },
         },
         'body' => Tuple:{
           'vars' => Relation:[ 'name', 'type', ]:{
             [ 'person_name', Cat.NameChain:'sys.std.Core.Type.Text', ],
             [ 'person_addr', Cat.NameChain:'sys.std.Core.Type.Text', ],
           },
           'stmts' => Seq:[
             Tuple:{
               'procedure' => 
Cat.NameChain:'sys.std.Core.STDIO.prompt_Text_line',
               'upd_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'target', Cat.NameChain:'lex.person_name', ],
               },
               'ro_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'prompt', Cat.NameChain:'lex.msg_gather_name', ],
               },
             },
             Tuple:{
               'procedure' => 
Cat.NameChain:'sys.std.Core.STDIO.prompt_Text_line',
               'upd_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'target', Cat.NameChain:'lex.person_addr', ],
               },
               'ro_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'prompt', Cat.NameChain:'lex.msg_gather_addr', ],
               },
             },
             Tuple:{
               'procedure' => Cat.NameChain:'inn.add_person',
               'upd_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'people', Cat.NameChain:'lex.people', ],
               },
               'ro_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'person_name', Cat.NameChain:'lex.person_name', ],
                 [ 'person_addr', Cat.NameChain:'lex.person_addr', ],
               },
             },
           ],
         },
       },

     },
     'inner_upds' => Relation:{

       {
         'name' => 'init_vars',
         'comment' => Cat.Comment:'Initializes main routine\qs variables.',
         'head' => Tuple:{
           'upd_params' => Relation:[ 'name', 'type', ]:{
             [ 'msg_gather_name', Cat.NameChain:'sys.std.Core.Type.Text', ],
             [ 'msg_gather_addr', Cat.NameChain:'sys.std.Core.Type.Text', ],
             [ 'msg_search_name', Cat.NameChain:'sys.std.Core.Type.Text', ],
             [ 'msg_result_addr', Cat.NameChain:'sys.std.Core.Type.Text', ],
             [ 'people', Cat.NameChain:'sys.std.Core.Type.Relation', ],
           },
         },
         'body' => Tuple:{
           'exprs' => Tuple:{
             'sca_lit_exprs' => Relation:[ 'name', 'value', ]:{
               [ 'emgn', Text:'Enter a person\qs name: ', ],
               [ 'emga', Text:'Enter that person\qs address: ', ],
               [ 'emsn', Text:'Enter a name to search for: ', ],
               [ 'emrn', Text:'Found address for that person is: ', ],
             },
             'rel_lit_exprs' => Relation:{
               {
                 'name' => 'ep',
                 'head' => Set:{ 'person_name', 'person_addr', },
                 'body' => Set:{},
               },
             },
           },
           'stmt' => Relation:{
             {
               'updater' => Cat.NameChain:'sys.std.Core.Universal.assign',
               'upd_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'target', Cat.NameChain:'lex.msg_gather_name', ],
               },
               'ro_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'v', Cat.NameChain:'lex.emgn', ],
               },
             },
             {
               'updater' => Cat.NameChain:'sys.std.Core.Universal.assign',
               'upd_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'target', Cat.NameChain:'lex.msg_gather_addr', ],
               },
               'ro_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'v', Cat.NameChain:'lex.emga', ],
               },
             },
             {
               'updater' => Cat.NameChain:'sys.std.Core.Universal.assign',
               'upd_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'target', Cat.NameChain:'lex.msg_search_name', ],
               },
               'ro_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'v', Cat.NameChain:'lex.emsn', ],
               },
             },
             {
               'updater' => Cat.NameChain:'sys.std.Core.Universal.assign',
               'upd_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'target', Cat.NameChain:'lex.msg_result_addr', ],
               },
               'ro_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'v', Cat.NameChain:'lex.emra', ],
               },
             },
             {
               'updater' => Cat.NameChain:'sys.std.Core.Universal.assign',
               'upd_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'target', Cat.NameChain:'lex.people', ],
               },
               'ro_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'v', Cat.NameChain:'lex.ep', ],
               },
             },
           },
         },
       },

       {
         'name' => 'add_person',
         'comment' => Cat.Comment:'Adds a person to our db of people.',
         'head' => Tuple:{
           'upd_params' => Relation:[ 'name', 'type', ]:{
             [ 'people', Cat.NameChain:'sys.std.Core.Type.Relation', ],
           },
           'ro_params' => Relation:[ 'name', 'type', ]:{
             [ 'person_name', Cat.NameChain:'sys.std.Core.Type.Text', ],
             [ 'person_addr', Cat.NameChain:'sys.std.Core.Type.Text', ],
           },
         },
         'body' => Tuple:{
           'exprs' => Tuple:{
             'tup_lit_exprs' => Relation:{
               {
                 'name' => 'person',
                 'attrs' => Relation:[ 'name', 'expr', ]:{
                   [ 'person_name', Cat.NameChain:'lex.person_name', ],
                   [ 'person_addr', Cat.NameChain:'lex.person_addr', ],
                 },
               },
             },
           },
           'stmt' => Relation:{
             {
               'updater' => 
Cat.NameChain:'sys.std.Core.Relation.assign_insertion',
               'upd_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'r', Cat.NameChain:'lex.people', ],
               },
               'ro_args' => Relation:[ 'name', 'expr', ]:{
                 [ 't', Cat.NameChain:'lex.person', ],
               },
             },
           },
         },
       },

       {
         'name' => 'search_for_address',
         'comment' => Cat.Comment:'Look up person name, get their address.',
         'head' => Tuple:{
           'upd_params' => Relation:[ 'name', 'type', ]:{
             [ 'person_addr', Cat.NameChain:'sys.std.Core.Type.Text', ],
           },
           'ro_params' => Relation:[ 'name', 'type', ]:{
             [ 'people', Cat.NameChain:'sys.std.Core.Type.Relation', ],
             [ 'person_name', Cat.NameChain:'sys.std.Core.Type.Text', ],
           },
         },
         'body' => Tuple:{
           'exprs' => Tuple:{
             'rel_lit_exprs' => Relation:{
               {
                 'name' => 'person_name_r',
                 'head' => Set:{ 'person_name', },
                 'body' => Set:{
                   Relation:[ 'name', 'expr', ]:{
                     [ 'person_name', Cat.NameChain:'lex.person_name', ],
                   },
                 },
               },
             },
             'func_invo_exprs' => Relation:{
               {
                 'name' => 'matched_people',
                 'function' => Cat.NameChain:'sys.std.Core.Relation.semijoin',
                 'args' => Relation:[ 'name', 'expr', ]:{
                   [ 'source', Cat.NameChain:'lex.people', ],
                   [ 'filter', Cat.NameChain:'lex.person_name_r', ],
                 },
               },
               {
                 'name' => 'matched_person',
                 'comment' => 'Note, we\qre assuming exactly one match.',
                 'function' => 
Cat.NameChain:'sys.std.Core.Relation.Tuple_from_Relation',
                 'args' => Relation:[ 'name', 'expr', ]:{
                   [ 'topic', Cat.NameChain:'lex.matched_person', ],
                 },
               },
             },
           },
           'stmt' => Relation:{
             {
               'updater' => Cat.NameChain:'sys.std.Core.Universal.assign',
               'upd_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'target', Cat.NameChain:'lex.person_addr', ],
               },
               'ro_args' => Relation:[ 'name', 'expr', ]:{
                 [ 'v', Cat.NameChain:'lex.matched_person.person_addr', ],
               },
             },
           },
         },
       },
     },
   },

};

boot_call:'fed.lib.app.main':{};


More information about the Victoria-pm mailing list