diff options
| -rw-r--r-- | m.html.markdown | 370 | 
1 files changed, 370 insertions, 0 deletions
| diff --git a/m.html.markdown b/m.html.markdown new file mode 100644 index 00000000..d0879ab6 --- /dev/null +++ b/m.html.markdown @@ -0,0 +1,370 @@ +---  +language: M (MUMPS) +contributors:  +    - ["Fred Turkington", "http://z3ugma.github.io"]  +filename: LEARNM.m  +--- + +M, or MUMPS (Massachusetts General Hospital Utility Multi-Programming System) is +a procedural language with a built-in NoSQL database. Or, it’s a database with +an integrated language optimized for accessing and manipulating that database. +A key feature of M is that accessing local variables in memory and persistent +storage use the same basic syntax, so there's no separate query +language to remember. This makes it fast to program with, especially for +beginners. M's syntax was designed to be concise in an era where +computer memory was expensive and limited. This concise style means that a lot +more fits on one screen without scrolling. + +The M database is a hierarchical key-value store designed for high-throughput +transaction processing. The database is organized into tree structures called +"globals", which are sparse data structures with parallels to modern formats +like JSON. + +Originally designed in 1966 for the healthcare applications, M continues to be +used widely by healthcare systems and financial institutions for high-throughput +real-time applications.  + +### Example + +Here's an example M program to calculate the Fibonacci series: + +``` +fib ; compute the first few Fibonacci terms +    new i,a,b,sum +    set (a,b)=1 ; Initial conditions +    for i=1:1 do  quit:sum>1000 +    . set sum=a+b +    . write !,sum +    . set a=b,b=sum +``` + +### Comments + +``` +;   Comments start with a semicolon (;) +``` +### Data Types + +M has two data types: + +``` +;   Numbers - no commas, leading and trailing 0 removed. +;       Scientific notation with 'E'. +;       Floats with IEEE 754 double-precision values (15 digits of precision) +;       Examples: 20, 1e3 (stored as 1000), 0500.20 (stored as 500.2) +;   Strings - Characters enclosed in double quotes. +;       "" is the null string. Use "" within a string for " +;       Examples: "hello", "Scrooge said, ""Bah, Humbug!""" +``` +### Commands + +Commands are case insensitive, and have a shortened abbreviation, often the first letter. Commands have zero or more arguments,depending on the command. M is whitespace-aware. Spaces are treated as a delimiter between commands and arguments. Each command is separated from its arguments by 1 space. Commands with zero arguments are followed by 2 spaces. + +#### W(rite) + +Print data to the current device. + +```  +WRITE !,"hello world"  +``` + +! is syntax for a new line. Multiple statements can be provided as additional arguments: + +``` +w !,"foo bar"," ","baz"  +``` + +#### R(ead) + +Retrieve input from the user + +``` +READ var +r !,"Wherefore art thou Romeo? ",why +``` +Multiple arguments can be passed to a read command. Constants are outputted. Variables are retrieved from the user. The terminal waits for the user to enter the first variable before displaying the second prompt. + +``` +r !,"Better one, or two? ",lorem," Better two, or three? ",ipsum +``` + +#### S(et) + +Assign a value to a variable + +``` +SET name="Benjamin Franklin" +s centi=0.01,micro=10E-6 +w !,centi,!,micro + +;.01 +;.00001 +``` +#### K(ill) + +Remove a variable from memory or remove a database entry from disk. + +``` +KILL centi +k micro +``` +### Globals and Arrays + +In addition to local variables, M has persistent variables stored to disk called _globals_. Global names must start with a __caret__ (__^__). Globals are the built-in database of M. + +Any variable can be an array with the assignment of a _subscript_. Arrays are sparse and do not have a predefined size. Arrays should be visualized like trees, where subscripts are branches and assigned values are leaves. Not all nodes in an array need to have a value.  + +``` +s ^cars=20 +s ^cars("Tesla",1,"Name")="Model 3" +s ^cars("Tesla",2,"Name")="Model X" +s ^cars("Tesla",2,"Doors")=5 + +w !,^cars  +; 20 +w !,^cars("Tesla") +; null value - there's no value assigned to this node but it has children +w !,^cars("Tesla",1,"Name") +; Model X +``` + +Arrays are automatically sorted in order. Take advantage of the built-in sorting by setting your value of interest as the last child subscript of an array rather than its value. + +``` +; A log of temperatures by date and time +s ^TEMPS("11/12","0600",32)="" +s ^TEMPS("11/12","1030",48)="" +s ^TEMPS("11/12","1400",49)="" +s ^TEMPS("11/12","1700",43)="" +``` +### Operators +```jinja +; Assignment:       = +; Unary:            +   Convert a string value into a numeric value. +; Arthmetic: +;                   +   addition +;                   -   subtraction +;                   *   multiplication +;                   /   floating-point division +;                   \   integer division +;                   #   modulo +;                   **  exponentiation +; Logical:   +;                   &   and +;                   !   or +;                   '   not +; Comparison: +;                   =   equal  +;                   '=  not equal +;                   >   greater than +;                   <   less than +;                   '>  not greater / less than or equal to +;                   '<  not less / greater than or equal to +; String operators: +;                   _   concatenate +;                   [   contains           a contains b  +;                   ]]  sorts after        a comes after b +;                   '[  does not contain +;                   ']] does not sort after +``` + +#### Order of operations + +Operations in M are _strictly_ evaluated left to right. No operator has precedence over any other. +You should use parentheses to group expressions. + +``` +w 5+3*20 +;160 +;You probably wanted 65 +w 5+(3*20)  +``` + +### Flow Control, Blocks, & Code Structure + +A single M file is called a _routine_. Within a given routine, you can break your code up into smaller chunks with _tags_. The tag starts in column 1 and the commands pertaining to that tag are indented. + +A tag can accept parameters and return a value, this is a function. A function is called with '$$': + +``` +; Execute the 'tag' function, which has two parameters, and write the result. +w !,$$tag^routine(a,b)  +``` + +M has an execution stack. When all levels of the stack have returned, the program ends. Levels are added to the stack with _do_ commands and removed with _quit_ commands. + +#### D(o) + +With an argument: execute a block of code & add a level to the stack.  + +``` +d ^routine    ;run a routine from the begining.  +;             ;routines are identified by a caret. +d tag         ;run a tag in the current routine +d tag^routine ;run a tag in different routine +``` + +Argumentless do: used to create blocks of code. The block is indented with a period for each level of the block: + +``` +set a=1 +if a=1 do   +. write !,a +. read b +. if b > 10 d +. . w !, b  +w "hello" +``` + +#### Q(uit) +Stop executing this block and return to the previous stack level. +Quit can return a value. + +#### N(ew) +Clear a given variable's value _for just this stack level_. Useful for preventing side effects. + +Putting all this together, we can create a full example of an M routine: + +``` +; RECTANGLE - a routine to deal with rectangle math +    q ; quit if a specific tag is not called + +main  +    n length,width ; New length and width so any previous value doesn't persist +    w !,"Welcome to RECTANGLE. Enter the dimensions of your rectangle." +    r !,"Length? ",length,!,"Width? ",width +    d area(length,width)            ;Do a tag +    s per=$$perimeter(length,width) ;Get the value of a function +    w !,"Perimeter: ",per +    q + +area(length,width)  ; This is a tag that accepts parameters.  +                    ; It's not a function since it quits with no value. +    w !, "Area: ",length*width +    q ; Quit: return to the previous level of the stack. + +perimeter(length,width) +    q 2*(length+width) ; Quits with a value; thus a function +``` + +### Conditionals, Looping and $Order() + +F(or) loops can follow a few different patterns: + +```jinja +;Finite loop with counter +;f var=start:increment:stop + +f i=0:5:25 w i," " ;0 5 10 15 20 25  + +; Infinite loop with counter +; The counter will keep incrementing forever. Use a conditional with Quit to get out of the loop. +;f var=start:increment  + +f j=1:1 w j," " i j>1E3 q ; Print 1-1000 separated by a space + +;Argumentless for - infinite loop. Use a conditional with Quit. +;   Also read as "forever" - f or for followed by two spaces. +s var="" +f  s var=var_"%" w !,var i var="%%%%%%%%%%" q   +; % +; %% +; %%% +; %%%% +; %%%%% +; %%%%%% +; %%%%%%% +; %%%%%%%% +; %%%%%%%%% +; %%%%%%%%%% + +``` + +#### I(f), E(lse), Postconditionals + +M has an if/else construct for conditional evaluation, but any command can be conditionally executed without an extra if statement using a _postconditional_. This is a condition that occurs immediately after the command, separated with a colon (:). + +```jinja +; Conditional using traditional if/else +r "Enter a number: ",num +i num>100 w !,"huge" +e i num>10 w !,"big" +e w !,"small" + +; Postconditionals are especially useful in a for loop. +; This is the dominant for loop construct: +;   a 'for' statement +;   that tests for a 'quit' condition with a postconditional +;   then 'do'es an indented block for each iteration + +s var="" +f  s var=var_"%" q:var="%%%%%%%%%%" d  ;Read as "Quit if var equals "%%%%%%%%%%" +. w !,var + +;Bonus points - the $L(ength) built-in function makes this even terser + +s var="" +f  s var=var_"%" q:$L(var)>10  d  ; +. w !,var + +``` +#### Array Looping - $Order +As we saw in the previous example, M has built-in functions called with a single $, compared to user-defined functions called with $$. These functions have shortened abbreviations, like commands. +One of the most useful is __$Order()__ / $O(). When given an array subscript, $O returns the next subscript in that array. When it reaches the last subscript, it returns "". + +```jinja +;Let's call back to our ^TEMPS global from earlier: +; A log of temperatures by date and time +s ^TEMPS("11/12","0600",32)="" +s ^TEMPS("11/12","0600",48)="" +s ^TEMPS("11/12","1400",49)="" +s ^TEMPS("11/12","1700",43)="" +; Some more +s ^TEMPS("11/16","0300",27)="" +s ^TEMPS("11/16","1130",32)="" +s ^TEMPS("11/16","1300",47)="" + +;Here's a loop to print out all the dates we have temperatures for: +n date,time ; Initialize these variables with "" + +; This line reads: forever; set date as the next date in ^TEMPS. +; If date was set to "", it means we're at the end, so quit. +; Do the block below +f  s date=$ORDER(^TEMPS(date)) q:date="" d +. w !,date + +; Add in times too: +f  s date=$ORDER(^TEMPS(date)) q:date=""  d +. w !,"Date: ",date +. f  s time=$O(^TEMPS(date,time)) q:time=""  d +. . w !,"Time: ",time + +; Build an index that sorts first by temperature -  +; what dates and times had a given temperature? +n date,time,temp +f  s date=$ORDER(^TEMPS(date)) q:date=""  d +. f  s time=$O(^TEMPS(date,time)) q:time=""  d +. . f  s temp=$O(^TEMPS(date,time,temp)) q:temp=""  d +. . . s ^TEMPINDEX(temp,date,time)="" + +;This will produce a global like +^TEMPINDEX(27,"11/16","0300") +^TEMPINDEX(32,"11/12","0600") +^TEMPINDEX(32,"11/16","1130") +``` + +## Further Reading + +There's lots more to learn about M. A great short tutorial comes from the University of Northern Iowa and  Professor Kevin O'Kane's [Introduction to the MUMPS Language][1] presentation. + +To install an M interpreter / database on your computer, try a [YottaDB Docker image][2].  + +YottaDB and its precursor, GT.M, have thorough documentation on all the language features including database transactions, locking, and replication: + +* [YottaDB Programmer's Guide][3] +* [GT.M Programmer's Guide][4] + +[1]: https://www.cs.uni.edu/~okane/source/MUMPS-MDH/MumpsTutorial.pdf  +[2]: https://yottadb.com/product/get-started/ +[3]: https://docs.yottadb.com/ProgrammersGuide/langfeat.html +[4]: http://tinco.pair.com/bhaskar/gtm/doc/books/pg/UNIX_manual/index.html | 
