FYI - Muldis D whole app code example

2 views
Skip to first unread message

Darren Duncan

unread,
Apr 24, 2009, 5:31:18 AM4/24/09
to muldis-db...@mm.darrenduncan.net, muldis-...@mm.darrenduncan.net, muldis-...@mm.darrenduncan.net, t...@thethirdmanifesto.com, recco...@googlegroups.com, victo...@pm.org
Hello,

This message is a follow-up to my post of a couple weeks ago, that showed
examples of individual Muldis D routine definitions side by side with SQL
statements (from the SQL::Abstract 2 module docs) whose work they did.

Today's message is a demonstration of the fact that (loosely SQL-alike) Muldis D
is computationally complete, that you actually could write a standalone program
in it if you wanted to, though in practice you would just use it for parts of
programs like you do SQL, which AFAIK is *not* computationally complete.

Below the dashed line in this message is a 3K example program which prompts the
user to enter the name and address of 3 people, with which it populates a
(lexical) relvar/table, and then it prompts the user to enter a name to search
for, and then it searches for and prints out the address that went with that
name, if it was found, and a not-found message otherwise.

All of the features that this program uses are already specced (see
http://search.cpan.org/dist/Muldis-D/ ) as usual, but that most of the concrete
syntax it uses is not formally specced yet.

A few notes:

1. This demo consists of exactly one program routine, called mymain, which due
to artifacts of the language's design such as separating pure code from impure
code (all value literals or value expressions must be in the pure section, while
all user interaction must be in the impure section), is internally segmented
into 5 inner routines; in most programming languages that would all just be a
single routine mixing pure and impure code. An "updater" is pure (and atomic)
while a "procedure" is impure.

2. Declaring the mymain routine requires mounting (analogous to SQL's CONNECT
TO) a database/depot, named myapp, to store it in (all Muldis D routines are
stored routines save the bootloader, which is mainly limited to stuffing things
in a depot and invoking them). In this case, the depot used is declared
temporary and so it is just kept in RAM, no disk file being created. Some other
time I'll demonstrate using a persisting depot like one would normally use for
data. In practice, an application would use 2 depots (each being their own
namespaces), one persistent for mainly data like a normal database, and one
possibly temporary for mainly code specific to that app; the example in this
email is like the latter.

3. One demonstrated improvement from the last email is that when invoking a
routine, up to 2 arguments may be passed without names (rather than just one
shown before), which is one readonly argument and one subject-to-update
argument, when just one of their respective kinds of parameters exists; they are
told apart in that subject-to-update are marked with an ampersand and readonly
doesn't have one.

4. Unlike the previous emails, this one includes examples of: user I/O (simple
command line STDIN/OUT), generic if/else expressions, factoring out an
otherwise-repeated part of a value expression into a named sub-expression
("matched_people"), and procedural iteration (but most iteration in a Muldis D
program would be functional).

-- Darren Duncan

----------

Muldis_D:"http://muldis.com":"0.65.0":PTMD_Tiny:bootloader

create depot_mount myapp {
is_temporary => true
we_may_update => true
}

within depot myapp create {

#=========================================================================#

procedure mymain () {
# This is the program's main procedure. #

main {
var Text $msg_gather_name
var Text $msg_gather_addr
var Text $msg_search_name
var Text $msg_result_addr
var Relation $people
var Text $name
var Text $addr
var NNInt $loop_count

inn.init_vars( &msg_gather_name => $msg_gather_name,
&msg_gather_addr => $msg_gather_addr,
&msg_search_name => $msg_search_name,
&msg_result_addr => $msg_result_addr, &people => $people,
&loop_count => $loop_count )

loop $loop_count {
inn.gather_person( &$people,
msg_gather_name => $msg_gather_name,
msg_gather_addr => $msg_gather_addr )
}

prompt_Text_line( &$name, $msg_search_name )
inn.search_for_address( &$addr, people => $people, name => $name )
write_Text( $msg_result_addr )
write_Text_line( $addr )
}

inner_updater init_vars (Text &$msg_gather_name,
Text &$msg_gather_addr, Text &$msg_search_name,
Text &$msg_result_addr, Relation &$people,
NNInt &$loop_count ) {
# Initializes main routine's variables. #
$msg_gather_name := 'Enter a person\as name: '
$msg_gather_addr := 'Enter that person\as address: '
$msg_search_name := 'Enter a name to search for: '
$msg_result_addr := 'Found address for that person is: '
$people := Relation:{ name, addr }
$loop_count := 3
}

inner_procedure gather_person (Relation &$people,
Text $msg_gather_name, Text $msg_gather_addr) {
# Gathers person info from user. #
var Text $name
var Text $addr
prompt_Text_line( &$name, $msg_gather_name )
prompt_Text_line( &$addr, $msg_gather_addr )
inn.add_person( &$people, name => $name, addr => $addr )
}

inner_updater add_person (Relation &$people, Text $name, Text $addr) {
# Adds a person to our db of people. #
assign_insertion( &$people,
Tuple:{ name => $name, addr => $addr } );
}

inner_updater search_for_address
(Text &$addr, Relation $people, Text $name) {
# Look up person by name, get their address. #
$matched_people = ($people matching Relation:{ { name => $name } })
$addr := (
if ((cardinality of $matched_people) === 1)
then ((tuple from $matched_people){A:addr})
else '<Not Exactly One Person Matched>'
)
}
}

#=========================================================================#

} # within depot myapp create #

boot_stmt fed.lib.myapp.mymain()

Reply all
Reply to author
Forward
0 new messages