From 55f277e77428d7423ae906a8e1f1324d35b07a7d Mon Sep 17 00:00:00 2001 From: Jakob Kaivo Date: Fri, 4 Mar 2022 12:32:20 -0500 Subject: import Miranda 2.066 from upstream --- miralib/.version | 1 + miralib/COPYING | 27 ++ miralib/auxfile | 28 ++ miralib/ex/README | 54 ++++ miralib/ex/ack.m | 9 + miralib/ex/barry.m | 31 ++ miralib/ex/box | 1 + miralib/ex/box.m | 244 +++++++++++++++ miralib/ex/divmodtest.m | 11 + miralib/ex/edigits.m | 73 +++++ miralib/ex/fib.m | 4 + miralib/ex/fibs.m | 16 + miralib/ex/genmat.m | 84 +++++ miralib/ex/graphics.m | 164 ++++++++++ miralib/ex/hamming.m | 19 ++ miralib/ex/hanoi.m | 11 + miralib/ex/just.m | 98 ++++++ miralib/ex/kate.lit.m | 138 ++++++++ miralib/ex/kate.pdf | Bin 0 -> 58803 bytes miralib/ex/kate.tex | 1 + miralib/ex/keith.m | 31 ++ miralib/ex/makebug.m | 18 ++ miralib/ex/matrix.m | 70 +++++ miralib/ex/mrev | 22 ++ miralib/ex/parafs.m | 33 ++ miralib/ex/polish.m | 34 ++ miralib/ex/powers.m | 15 + miralib/ex/primes.m | 7 + miralib/ex/pyths.m | 9 + miralib/ex/queens.m | 22 ++ miralib/ex/queens1.m | 16 + miralib/ex/quicksort.m | 12 + miralib/ex/rational.m | 56 ++++ miralib/ex/refoliate.m | 60 ++++ miralib/ex/selflines.m | 32 ++ miralib/ex/set.m | 64 ++++ miralib/ex/stack.m | 19 ++ miralib/ex/topsort.m | 32 ++ miralib/ex/treesort.m | 20 ++ miralib/ex/unify.m | 79 +++++ miralib/helpfile | 25 ++ miralib/manual/.epoch | 1 + miralib/manual/1 | 76 +++++ miralib/manual/10 | 60 ++++ miralib/manual/100 | 578 ++++++++++++++++++++++++++++++++++ miralib/manual/11 | 86 +++++ miralib/manual/12 | 86 +++++ miralib/manual/13/1 | 22 ++ miralib/manual/13/2 | 68 ++++ miralib/manual/13/3 | 33 ++ miralib/manual/13/contents | 6 + miralib/manual/14 | 66 ++++ miralib/manual/15 | 92 ++++++ miralib/manual/16 | 174 +++++++++++ miralib/manual/17 | 66 ++++ miralib/manual/18 | 114 +++++++ miralib/manual/19 | 18 ++ miralib/manual/2 | 23 ++ miralib/manual/20 | 126 ++++++++ miralib/manual/21 | 133 ++++++++ miralib/manual/22 | 35 +++ miralib/manual/23 | 55 ++++ miralib/manual/24 | 58 ++++ miralib/manual/25 | 80 +++++ miralib/manual/26 | 72 +++++ miralib/manual/27/1 | 19 ++ miralib/manual/27/2 | 44 +++ miralib/manual/27/3 | 286 +++++++++++++++++ miralib/manual/27/4 | 116 +++++++ miralib/manual/27/5 | 132 ++++++++ miralib/manual/27/contents | 8 + miralib/manual/28 | 1 + miralib/manual/29 | 1 + miralib/manual/29.m | 88 ++++++ miralib/manual/3 | 55 ++++ miralib/manual/30 | 261 ++++++++++++++++ miralib/manual/31/1 | 92 ++++++ miralib/manual/31/2 | 138 ++++++++ miralib/manual/31/3 | 42 +++ miralib/manual/31/4 | 175 +++++++++++ miralib/manual/31/5 | 105 +++++++ miralib/manual/31/6 | 38 +++ miralib/manual/31/7 | 160 ++++++++++ miralib/manual/31/8 | 83 +++++ miralib/manual/31/9 | 54 ++++ miralib/manual/31/contents | 12 + miralib/manual/32 | 98 ++++++ miralib/manual/33 | 4 + miralib/manual/34 | 87 ++++++ miralib/manual/4 | 147 +++++++++ miralib/manual/5 | 1 + miralib/manual/6 | 1 + miralib/manual/7 | 81 +++++ miralib/manual/8 | 75 +++++ miralib/manual/9 | 62 ++++ miralib/manual/99 | 5 + miralib/manual/contents | 22 ++ miralib/manual/howtoprint | 4 + miralib/manual/permission | 6 + miralib/manual/printman | 42 +++ miralib/menudriver.csh | 104 +++++++ miralib/menudriver.sh | 102 ++++++ miralib/prelude | 110 +++++++ miralib/stdenv.m | 761 +++++++++++++++++++++++++++++++++++++++++++++ 104 files changed, 7440 insertions(+) create mode 100644 miralib/.version create mode 100644 miralib/COPYING create mode 100644 miralib/auxfile create mode 100644 miralib/ex/README create mode 100644 miralib/ex/ack.m create mode 100644 miralib/ex/barry.m create mode 120000 miralib/ex/box create mode 100755 miralib/ex/box.m create mode 100644 miralib/ex/divmodtest.m create mode 100644 miralib/ex/edigits.m create mode 100644 miralib/ex/fib.m create mode 100644 miralib/ex/fibs.m create mode 100644 miralib/ex/genmat.m create mode 100644 miralib/ex/graphics.m create mode 100644 miralib/ex/hamming.m create mode 100644 miralib/ex/hanoi.m create mode 100644 miralib/ex/just.m create mode 100644 miralib/ex/kate.lit.m create mode 100644 miralib/ex/kate.pdf create mode 120000 miralib/ex/kate.tex create mode 100644 miralib/ex/keith.m create mode 100644 miralib/ex/makebug.m create mode 100644 miralib/ex/matrix.m create mode 100755 miralib/ex/mrev create mode 100644 miralib/ex/parafs.m create mode 100644 miralib/ex/polish.m create mode 100644 miralib/ex/powers.m create mode 100644 miralib/ex/primes.m create mode 100644 miralib/ex/pyths.m create mode 100644 miralib/ex/queens.m create mode 100644 miralib/ex/queens1.m create mode 100644 miralib/ex/quicksort.m create mode 100644 miralib/ex/rational.m create mode 100644 miralib/ex/refoliate.m create mode 100644 miralib/ex/selflines.m create mode 100644 miralib/ex/set.m create mode 100644 miralib/ex/stack.m create mode 100644 miralib/ex/topsort.m create mode 100644 miralib/ex/treesort.m create mode 100644 miralib/ex/unify.m create mode 100644 miralib/helpfile create mode 100644 miralib/manual/.epoch create mode 100644 miralib/manual/1 create mode 100644 miralib/manual/10 create mode 100644 miralib/manual/100 create mode 100644 miralib/manual/11 create mode 100644 miralib/manual/12 create mode 100644 miralib/manual/13/1 create mode 100644 miralib/manual/13/2 create mode 100644 miralib/manual/13/3 create mode 100644 miralib/manual/13/contents create mode 100644 miralib/manual/14 create mode 100644 miralib/manual/15 create mode 100644 miralib/manual/16 create mode 100644 miralib/manual/17 create mode 100644 miralib/manual/18 create mode 100644 miralib/manual/19 create mode 100644 miralib/manual/2 create mode 100644 miralib/manual/20 create mode 100644 miralib/manual/21 create mode 100644 miralib/manual/22 create mode 100644 miralib/manual/23 create mode 100644 miralib/manual/24 create mode 100644 miralib/manual/25 create mode 100644 miralib/manual/26 create mode 100644 miralib/manual/27/1 create mode 100644 miralib/manual/27/2 create mode 100644 miralib/manual/27/3 create mode 100644 miralib/manual/27/4 create mode 100644 miralib/manual/27/5 create mode 100644 miralib/manual/27/contents create mode 120000 miralib/manual/28 create mode 120000 miralib/manual/29 create mode 100644 miralib/manual/29.m create mode 100644 miralib/manual/3 create mode 100644 miralib/manual/30 create mode 100644 miralib/manual/31/1 create mode 100644 miralib/manual/31/2 create mode 100644 miralib/manual/31/3 create mode 100644 miralib/manual/31/4 create mode 100644 miralib/manual/31/5 create mode 100644 miralib/manual/31/6 create mode 100644 miralib/manual/31/7 create mode 100644 miralib/manual/31/8 create mode 100644 miralib/manual/31/9 create mode 100644 miralib/manual/31/contents create mode 100644 miralib/manual/32 create mode 100644 miralib/manual/33 create mode 100644 miralib/manual/34 create mode 100644 miralib/manual/4 create mode 120000 miralib/manual/5 create mode 120000 miralib/manual/6 create mode 100644 miralib/manual/7 create mode 100644 miralib/manual/8 create mode 100644 miralib/manual/9 create mode 100755 miralib/manual/99 create mode 100644 miralib/manual/contents create mode 100644 miralib/manual/howtoprint create mode 100644 miralib/manual/permission create mode 100755 miralib/manual/printman create mode 100755 miralib/menudriver.csh create mode 100755 miralib/menudriver.sh create mode 100644 miralib/prelude create mode 100644 miralib/stdenv.m (limited to 'miralib') diff --git a/miralib/.version b/miralib/.version new file mode 100644 index 0000000..0e21d5e --- /dev/null +++ b/miralib/.version @@ -0,0 +1 @@ +2066 diff --git a/miralib/COPYING b/miralib/COPYING new file mode 100644 index 0000000..2dd23d0 --- /dev/null +++ b/miralib/COPYING @@ -0,0 +1,27 @@ +The Miranda system is Copyright (c) Research Software Limited, +1985-2020 + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + diff --git a/miralib/auxfile b/miralib/auxfile new file mode 100644 index 0000000..f0c3b7f --- /dev/null +++ b/miralib/auxfile @@ -0,0 +1,28 @@ +LIST OF REMAINING COMMANDS: + +/aux /a print this list of auxiliary commands +/cd [dirname] change directory (defaults to home directory) +/count (/nocount) statistics following each evaluation (default off) +/dic report size of dictionary for storing names etc +/editor report name of text editor used by ?? and /e commands +/editor PROG *change resident editor to PROG (see below) +/find id(s) like `?ids' but look under original names of aliases +/gc (/nogc) enable garbage collection reports (default off) +/heap report size of heap +/heap SIZE set heap to SIZE cells +/hush (/nohush) control prompts and other feedback (default on) +/list (/nolist) *control listing of script when compiling (default off) +/miralib report absolute pathname of the directory miralib +/(no)recheck *control busy checking for script updates (default off) +/settings /s print current settings of controllable options +/version /v print version information +/V more detailed version information +||... lines beginning in `||' are ignored (comment facility) + +notes:- +commands marked (*) are sticky, i.e. remembered for subsequent sessions +if you don't like the resident editor choose another - recommended editors +include - vi, joe, pico, nano, emacs - for more info see /man section 31(5) +/recheck enables a check for update of any relevant source file before +each evaluation, instead of only after /e[dit] - appropriate if an +editor window is kept open alongside the mira session window. diff --git a/miralib/ex/README b/miralib/ex/README new file mode 100644 index 0000000..3a68794 --- /dev/null +++ b/miralib/ex/README @@ -0,0 +1,54 @@ +This directory contains a (fairly random) collection of simple scripts +written in Miranda. To try one out (eg fibs.m) say + mira fibs +as a UNIX command - or if you are already inside a Miranda session, say + /f fibs +to make (e.g.) fibs.m your current script. To get into this directory, +while in a Miranda session, say + /cd + +Each script has some explanatory comments in it. To read the current +script from within a Miranda session say + /e +which invokes the editor on the current script. The scripts are listed +in groups, with some more advanced examples towards the end. The ones +marked (*) may be useful as libraries. + +ack.m the ackermann function +divmodtest.m tests properties of div and mod +fibs.m tabulates fibonacci numbers +hanoi.m solves the problem `towers of hanoi' +powers.m prints a table of powers +primes.m infinite list of prime numbers +pyths.m generates pythagorean triangles + +hamming.m prints hamming numbers +queens.m all solutions to the eight queens problem +queens1.m finds one solution to the eight queens problem +quicksort.m Miranda definition of quicksort +selflines.m curiosity - a self describing scroll of lines +stack.m defines stack as an abstract data type +treesort.m Miranda definition of treesort + +parafs.m Enumerates isomers of alkanes in pictorial form +graphics.m Rectangular graphics package used by parafs.m +keith.m Checks that floating point overflow is trapped +barry.m Math calculations that stress the garbage collector +bigscript.m Tests gc during compilation +makebig.m Creates bigscript.m of any chosen size + +edigits.m infinite decimal expansion of the digits of `e' (literate script) +rational.m package for doing rational arithmetic (*) +refoliate.m a tree problem (literate script) +topsort.m topological sort +matrix.m matrix package (*) +set.m defines set as an abstract data type (*) +kate.lit.m a Miranda script that is also a LaTeX source file + +genmat.m parameterised version of matrix package (*) +just.m text formatting program +mrev (executable) Miranda version of the UNIX `rev' command +box.m (executable) program for reboxing Miranda comments +box symbolic link to box.m +polish.m testbed for unify.m +unify.m package for doing 1st order unification (*) diff --git a/miralib/ex/ack.m b/miralib/ex/ack.m new file mode 100644 index 0000000..8a743eb --- /dev/null +++ b/miralib/ex/ack.m @@ -0,0 +1,9 @@ +||defines ackermann's function, beloved of recursion theorists. Example +|| ack 3 3 +||should yield 61, after doing a huge amount of recursion. Can only be +||called for small arguments, because the values get so big. + +ack 0 n = n+1 +ack (m+1) 0 = ack m 1 +ack (m+1) (n+1) = ack m (ack (m+1) n) +ack m n = error "ack applied to -ve or fractional arg" diff --git a/miralib/ex/barry.m b/miralib/ex/barry.m new file mode 100644 index 0000000..f93af80 --- /dev/null +++ b/miralib/ex/barry.m @@ -0,0 +1,31 @@ +||from Barry Brown, Sierra College -- Aug 2009 +||the critical case is test5, below + +|| Given a number, return the next number in the Collatz sequence +collatz :: num -> num +collatz n = n div 2, if (n mod 2 = 0) + = 3*n+1, if (n mod 2 = 1) + +|| Given a number, return the whole Collatz sequence starting with that +|| number. Note that it does not include the '1' on the end, but that's OK +|| since we're only interested in the length. +collatzseq n = takewhile (>1) (iterate collatz n) + +|| Given a number, return a tuple with the starting number and the +|| length of the Collatz sequence. We'll find the maximum tuple using the +|| next function. The number returned will be 1 less than the actual +|| Collatz sequence length, but that's OK for our purposes. One one of them +|| will be the longest. +collatzpair n = (n, #(collatzseq n)) + +|| Given two tuples, return the greater based on the second term. +maxtuple :: (*,**)->(*,**)->(*,**) +maxtuple x y = x, if (snd x > snd y) + = y, otherwise + + +test1 = map collatzpair [1..9] +test2 = foldr maxtuple (1,0) (map collatzpair [1..9]) +test3 = foldr maxtuple (1,0) (map collatzpair [1..999]) +test4 = foldr maxtuple (1,0) (map collatzpair [1..9999]) +test5 = foldl maxtuple (1,0) (map collatzpair [1..999999]) ||segfaults, ok with foldl diff --git a/miralib/ex/box b/miralib/ex/box new file mode 120000 index 0000000..be14d99 --- /dev/null +++ b/miralib/ex/box @@ -0,0 +1 @@ +box.m \ No newline at end of file diff --git a/miralib/ex/box.m b/miralib/ex/box.m new file mode 100755 index 0000000..87d404c --- /dev/null +++ b/miralib/ex/box.m @@ -0,0 +1,244 @@ +#! /home/dat/mira/states/src/miranda/mira -exec +|| Contributed by John Cupitt, University of Kent + +||A while ago Steve Hill (I think) appealed for useful Miranda programs +||-- well, here is the greatest productivity aid for Miranda hackers +||since ball-point pens. A 'vi' type filter to *rebox your comments*!! +||Amazing. It turns dull, unexciting notes like: + +|| Given a node in the tree, +||examine the branches and chose the exit with the +|| highest score. + +||into: + +||----------------------------------------------------------------------|| +|| Given a node in the tree, examine the branches and chose the exit || +|| with the highest score. || +||----------------------------------------------------------------------|| + +||Any comments welcome -- my Miranda is not as hot as it could be ... + +||John + +||----------------------------------------------------------------------|| +|| Box up Miranda comments. A filter from stdin to stdout +|| do_box :: [char] -> [char] || +|| - Strip ||s, reformat, rebox. || +||----------------------------------------------------------------------|| + +main = [Stdout (do_box $-)] + +||----------------------------------------------------------------------|| +|| Reboxing done in a pipeline of five stages. || +|| - Split the input into lines || +|| - Strip '||'s from input || +|| - Lex the input, breaking into tokens || +|| - Rejig tokens to produce fmted type output || +|| - Output tokens as [char] with a box drawn around them || +|| Formatting rules: || +|| - Lines starting '||-' are deleted || +|| - Leading & trailing '||' removed || +|| - Lines starting with a tab are not reformatted || +|| - Blank lines are 'new paragraph' || +||----------------------------------------------------------------------|| + +||----------------------------------------------------------------------|| +|| First a few types and useful little functions. || +||----------------------------------------------------------------------|| + +|| Useful constants +outWid = 68 || Width of the text in our boxes +boxWid = 72 || Size of the box we draw + +|| A token +tok ::= Word [char] | Newpara | Line [char] + +|| Useful character classifier +whitespace :: char -> bool +whitespace ch + = True, if ch = '\n' \/ ch = '\t' \/ ch = ' ' + = False, otherwise + +|| An edge of a box boxWid across +edge :: [char] +edge = "||" ++ (rep (boxWid-2) '-') ++ "||\n" + +|| Find the length of a line containing tabs +len :: [char] -> num +len str + = len' 0 str + where + len' n [] + = n + len' n (a:rest) + = len' (n+tab_space) rest, if a = '\t' + = len' (n+1) rest, otherwise + where + tab_space + = 8 - (n mod 8) + +|| Useful when doing output --- only attach first param if its not []. +no_blank :: [char] -> [[char]] -> [[char]] +no_blank a b + = a : b, if a ~= [] + = b, otherwise + +||----------------------------------------------------------------------|| +|| The main function. Call from a shell script in your /bin directory || +|| looking something like: || +|| #! /usr/bin/mira -exec || +|| main = [Stdout (do_box $-)] || +|| %include "../mira/box/box.m" || +||----------------------------------------------------------------------|| + +do_box :: [char] -> [char] +do_box input + = edge ++ rejig input ++ edge + where + rejig = re_box . format . lex_start . strip_start . split + +||----------------------------------------------------------------------|| +|| The first stage in processing. Split the input [char] into lines as || +|| [[char]]. || +||----------------------------------------------------------------------|| + +|| Split the text into a list of lines +split :: [char] -> [[char]] +split input + = split' [] input + where + split' sofar (a:input) + = sofar : split input, if a = '\n' + = split' (sofar ++ [a]) input, otherwise + split' sofar [] + = no_blank sofar [] || No extra blank lines! + +||----------------------------------------------------------------------|| +|| The next stage ... strip old '||'s from the input. Remove: || +|| - Lines starting '||-' || +|| - Strip leading '||'s || +|| - Strip trailing '||'s & trailing spaces || +||----------------------------------------------------------------------|| + +|| At the start of a line: +strip_start :: [[char]] -> [[char]] +strip_start ([]:input) + = [] : strip_start input || Keep blank lines +strip_start (('|':'|':line):input) + = strip_start' line + where + strip_start' ('-':rest) + = strip_start input || Strip '||---||' lines + strip_start' rest + = strip_rest rest input || Strip leading '||' +strip_start (line:input) + = strip_rest line input || Pass rest through +strip_start [] + = [] + +|| Scan along the rest of the line looking for trailing '||'s to strip. +strip_rest :: [char] -> [[char]] -> [[char]] +strip_rest line input + = strip_rest' (rev line) input + where + strip_rest' ('|':'|':rest) input + = strip_rest' rest input || Strip trailing || + strip_rest' (x:rest) input + = strip_rest' rest input, if whitespace x + strip_rest' line input + = (rev line) : strip_start input + +|| Efficient(ish) reverse +rev list + = rev' [] list + where + rev' sofar (a:x) + = rev' (a:sofar) x + rev' sofar [] + = sofar + +||----------------------------------------------------------------------|| +|| The next stage ... Break the input into Word, Newpara and Line || +|| tokens. Newpara for blank lines and line starting with space; Line || +|| for lines starting with a tab. || +||----------------------------------------------------------------------|| + +|| At the start of a line. +lex_start :: [[char]] -> [tok] +lex_start ([]:input) + = Newpara : lex_start input || Preserve blank lines +lex_start (('\t':rest):input) + = Line ('\t':rest) : lex_start input || Don't format tab lines +lex_start (line:input) + = lex_rest (strip_ws line) input || Lex to eol +lex_start [] + = [] + +|| In the middle of a line. Try to take words off the front of what we +|| have so far. +lex_rest :: [char] -> [[char]] -> [tok] +lex_rest [] input + = lex_start input +lex_rest sofar input + = Word wd : lex_rest (strip_ws rest) input + where + (wd, rest) + = break_word sofar + +|| Strip ws from the start of the line +strip_ws (a:input) + = (a:input), if ~whitespace a + = strip_ws input, otherwise +strip_ws [] + = [] + +|| Break the word from the front of a line of text. Return the remains +|| of the line along with the word. +break_word :: [char] -> ([char], [char]) +break_word (a:line) + = ([a] ++ rest, tag), if ~whitespace a + = ([], (a:line)), otherwise + where + (rest, tag) + = break_word line +break_word [] + = ([],[]) + +||----------------------------------------------------------------------|| +|| Almost the last stage ... Turn [tok] back into [[char]]. Format || +|| onto outWid character lines. || +||----------------------------------------------------------------------|| + +format :: [tok] -> [[char]] +format input + = format' [] input + where + format' sofar (Word wd:rest) + = format' (sofar ++ " " ++ wd) rest, if #sofar + #wd < outWid + = sofar : format' (" " ++ wd) rest, otherwise + format' sofar (Newpara:rest) + = no_blank sofar ([] : format rest) + format' sofar (Line line:rest) + = no_blank sofar (line : format rest) + format' sofar [] + = no_blank sofar [] + +||----------------------------------------------------------------------|| +|| The final stage. Box up a list of formatted lines. Try to be clever || +|| about using tabs on the ends of lines. || +||----------------------------------------------------------------------|| + +|| Draw a box boxWid across. +re_box :: [[char]] -> [char] +re_box (line:rest) + = "||" ++ line ++ padding ++ "||\n" ++ (re_box rest) + where + padding + = rep n_tab '\t' + n_tab + = (boxWid - line_length + 7) div 8 + line_length + = len ("||" ++ line) +re_box [] + =[] diff --git a/miralib/ex/divmodtest.m b/miralib/ex/divmodtest.m new file mode 100644 index 0000000..28b5e03 --- /dev/null +++ b/miralib/ex/divmodtest.m @@ -0,0 +1,11 @@ +||This script defines tests for three properties of div and mod, each +||checked over a small range of values including various combinations +||of signs. Each test should yield the result True, or there is +||something wrong with the arithmetic on your machine! + +test1 = and [a div b = entier (a/b) | a,b <- [-15..15]; b~=0] +test2 = and [b*(a div b) + a mod b = a | a,b <- [-15..15]; b~=0] +test3 = and [ ok a b | a,b <- [-15..15]; b~=0] + where + ok a b = 0 <= a mod b < b, if b>0 + = b < a mod b <= 0, if b<0 diff --git a/miralib/ex/edigits.m b/miralib/ex/edigits.m new file mode 100644 index 0000000..216757f --- /dev/null +++ b/miralib/ex/edigits.m @@ -0,0 +1,73 @@ +> ||note that this is a literate script + +Programming example - generating the digits of `e' + +We wish to write a program to generate the (decimal) digits of `e', as +an infinite string. Fact - the value of `e', the base of natural +logarithms, is given by the series + +e = 1 + 1/1! + 1/2! + 1/3! + ... + +where by n! we mean the factorial of n, = n*(n-1)...*2*1. Now, we can +choose to represent fractional numbers using a peculiar base system, in +which the weight of the i'th digit after the point is 1/i! (so note that +the `carry factor' by which we must multiply a unit from the i'th digit +when carrying it back to the i-1'th is i). Written to this funny base, +`e' is just + 2.1111111111............ +so the string we require may be obtained by converting fractional part +of the above numeral from the `funny base' to decimal. Thus + +> edigits = "2." ++ convert (repeat 1) + +The function `convert' takes for its argument a fraction in the funny +base (here represented as an infinite list of numbers) and returns its +value in decimal, as an infinite list of digits. The algorithm for +converting a fraction from another base to decimal, is as follows: (i) +multiply all digits by ten, and renormalise, using the appropriate carry +factors (ii) the whole number part of the result gives the first decimal +digit (iii) repeat the process on the fractional part of the result to +generate the remaining digits. Thus + +> convert x = mkdigit (hd x'):convert (tl x') +> where x' = norm 2 (0:map (10*) x) +> mkdigit n = decode(n + code '0'), if n<10 + +It remains to define the function `norm' which does renormalisation. A +naive (and almost correct) definition is + + norm c (d:x) = d + e' div c: e' mod c : x' + where + (e':x') = norm (c+1) x + +However, this is not a well-founded recursion, since it must search +arbitrarily far to the right in the fraction being normalised before +printing the first digit. If you try printing `edigits' with the above +as your definition of norm, you will get "2." followed by a long +silence. + +We need a theorem which will limit the distance from which a carry can +propagate. Fact: during the conversion of this fraction the maximum +possible carry from a digit to its leftward neighbour is 9. (The proof +of this, left as a (not very hard) exercise for the mathematically +minded reader, is by induction on the number of times the conversion +algorithm is applied.) This leads us to the following slightly more +cautious definition of `norm' + +> norm c (d:e:x) = d + e div c: e' mod c : x', if e mod c + 9 < c +> = d + e' div c : e' mod c : x', otherwise +> where +> (e':x') = norm (c+1) (e:x) + +Our solution is now complete. To see the results, enter mira with this +file as the current script and say + edigits +Hit control-C (interrupt) when you have seen enough digits. + +[Note: If nothing happens until you interrupt the evaluation, this may +be because the output from Miranda to your terminal is being +line-buffered, so the characters are not appearing on your screen as +Miranda prints them, but being saved up until there is a whole line to +print. Output from the computer to your terminal should not be line +buffered when Miranda is running - ask someone how to disable the line +buffering, if this is the case.] diff --git a/miralib/ex/fib.m b/miralib/ex/fib.m new file mode 100644 index 0000000..d84d33f --- /dev/null +++ b/miralib/ex/fib.m @@ -0,0 +1,4 @@ +||fib n computes the n'th fibonacci number +||by using /count you can estimate the asymptotic limit of (fib n/time to compute fib n) +fib n = 1, if n<=2 + = fib(n-1) + fib(n-2), otherwise diff --git a/miralib/ex/fibs.m b/miralib/ex/fibs.m new file mode 100644 index 0000000..39c805d --- /dev/null +++ b/miralib/ex/fibs.m @@ -0,0 +1,16 @@ +||This program tabulates the values of `fib i' a function for computing +||fibonacci numbers, in a list `fibs'. Because the function is memoised +||(i.e. it uses table lookup when it recurses) it runs in linear time. +||To see the fibonacci numbers say. +|| test + +fibs = map fib [0..] +fib 0 = 0 +fib 1 = 1 +fib (n+2) = fibs!(n+1) + fibs!n + +test = layn (map shownum fibs) + +||P.S. There is a more direct way of defining fibs, using a list comprehension +|| fibs = [a | (a,b) <- (0,1), (b,a+b) .. ] +||this also runs in linear time diff --git a/miralib/ex/genmat.m b/miralib/ex/genmat.m new file mode 100644 index 0000000..27c2f88 --- /dev/null +++ b/miralib/ex/genmat.m @@ -0,0 +1,84 @@ +||The matrix package again, but this time parameterised over an arbitrary +||element type, with a zero, a unit and four functions of arithmetic. +||Example - to instantiate this package with numbers as the element type, +||in another script, say:- +|| %include { elem==num; zero=0; unit=1; +|| plus=+; minus=-; times=*; divide=/; } + +||However another possibility would be to use the package to do matrix +||calculations over rationals (as defined in ) thus:- +|| %include +|| { elem==rational; zero=mkrat 0; unit=mkrat 1; +|| plus=rplus; minus=rminus; times=rtimes; divide=rdiv; } + +%export matrix idmat matadd matsub matmult prescalmult postscalmult + mkrow mkcol det adjoint inv + +%free { elem::type; zero,unit::elem; + plus,minus,times,divide::elem->elem->elem; + } + +matrix == [[elem]] + +idmat :: num->matrix ||identity matrix of given size +idmat n = [[delta i j|j<-[1..n]]|i<-[1..n]] + where + delta i j = unit, if i=j + = zero, otherwise + +matadd :: matrix->matrix->matrix +matadd x y = map2 vadd x y + where + vadd x y = map2 plus x y + +matsub :: matrix->matrix->matrix +matsub x y = map2 vsub x y + where + vsub = map2 minus + +matmult :: matrix->matrix->matrix +matmult x y = outer inner x (transpose y) ||* +inner x y = summate (map2 times x y) +outer f x y = [[f a b|b<-y]|a<-x] + +||*note that transpose is already defined in the standard environment + +summate = foldl plus zero + +prescalmult :: elem->matrix->matrix ||premultiply a matrix by a scalar +prescalmult n x = map (map (times n)) x + +postscalmult :: elem->matrix->matrix ||postmultiply a matrix by a scalar +postscalmult n x = map (map ($times n)) x + +||we need both the above because element multiplication may not be +||commutative + +mkrow :: [elem]->matrix ||make vector into matrix with a single row +mkrow x = [x] + +mkcol :: [elem]->matrix ||make vector into matrix with a single column +mkcol x = map (:[]) x + +det :: matrix->elem ||determinant, of square matrix +det [[a]] = a +det xs = summate [(xs!0!i) $times cofactor 0 i xs|i<-index xs], if #xs=#xs!0 + = error "det of nonsquare matrix", otherwise +cofactor i j xs = parity (i+j) $times det (minor i j xs) +minor i j xs = [omit j x | x<-omit i xs] +omit i x = take i x ++ drop (i+1) x + +parity::num->elem +parity i = unit, if i mod 2 = 0 + = zero $minus unit, otherwise + +adjoint :: matrix->matrix ||adjoint, of square matrix +adjoint xs = transpose[[cofactor i j xs | j<-index xs] | i <- index xs] + +inv :: matrix->matrix ||inverse, of non-singular square matrix +inv xs = transpose[[cofactor i j xs $divide h | j<-index xs] | i <- index xs] + where + h = det xs +||The above is a literal transcription of the mathematical definition of +||matrix inverse. A less naive version of the package would rewrite +||this to use Gaussian elimination. diff --git a/miralib/ex/graphics.m b/miralib/ex/graphics.m new file mode 100644 index 0000000..ca2f09a --- /dev/null +++ b/miralib/ex/graphics.m @@ -0,0 +1,164 @@ +||package for developing rectangular pictures composed of ascii characters +||DT Jan 84 +||all pictures are conceived as lying in an infinite plane with origin at (0,0) +||and filled with blanks except where non-blank chars have been specified +query * ::= FAIL | SUCCEED * +||generic union type, often useful -- should probably be in library +picture ::= MKPIC (num,num)! [[char]] | EMPTYPIC +||MKPIC holds a figure with its north west corner at the given coordinates +frame :: picture->(num,num,num,num) +||returns (left,right,low,high) of smallest rectangle containing the figure +frame(MKPIC (x,y) a) = (x,x+#a!0-1,y-#a+1,y) +||it is an error to apply frame to the empty picture +printpic :: picture->[char] ||prints pic with frame north west justified +printpic EMPTYPIC = [] +printpic (MKPIC (x,y) a) = concat[p ++ "\n" | p <- a] +printpic1 :: picture->[char] ||likewise, right shifted 8 +printpic1 EMPTYPIC = [] +printpic1 (MKPIC (x,y) a) = concat[" "++p ++ "\n" | p <- a] +alignpic :: num->num->picture->[char] +||prints picture as seen looking south east from the given cooordinates -- +||only parts of the figure onside from this position appear of course +alignpic x y EMPTYPIC = [] +alignpic x y (MKPIC (x1,y1) a) + = newlines (y-y1) ++ concat a1, if y>y1 + = concat(drop (y1-y) a1), if yx1 + = [spaces (x1-x) ++ p ++ "\n" | p <- a], if xnum->picture->picture ||move picture x right and y up +translate x y EMPTYPIC = EMPTYPIC +translate x y (MKPIC (x1,y1) a) = MKPIC (x+x1,y+y1) a +rotate :: num->picture->picture +||rotate the picture by n*pi/2 radians anticlockwise about (0,0) +rotate n EMPTYPIC = EMPTYPIC +rotate 0 = id +rotate 1 = reflect 3.reflect 2 ||result from group theory +rotate 2 (MKPIC (x,y) a) = + MKPIC (-(x+#a!0-1),-(y-#a+1)) (reverse (map reverse a)) +rotate 3 = reflect 2.reflect 3 ||group theory +rotate n = rotate (n mod 4) ||other values of n +reflect :: num->picture->picture +||reflect about a line inclined at n*pi/4 to the x axis +reflect n EMPTYPIC = EMPTYPIC +reflect 0 (MKPIC (x,y) a) = MKPIC (x,-(y-#a+1)) (reverse a) +reflect 1 = reflect 3.rotate 2 ||group theory +reflect 2 (MKPIC (x,y) a) = MKPIC (-(x+#a!0-1),y) (map reverse a) +reflect 3 (MKPIC (x,y) a) = MKPIC (-y,-x) (transpose a') + where a' = map(map f)a + f '-' = '|' + f '|' = '-' + f etc = etc +reflect n = reflect (n mod 4) ||other values of n +composepic :: [picture]->query picture +||tries to combine the given list of pictures to yield a composite picture +|| -- fails if any parts of the figures overlap +composepic = foldr apic (SUCCEED EMPTYPIC) +compositions :: [[picture]]->[picture] +||finds all possible ways of composing a picture (with no overlaps) with +||one component from each of the given picture lists +||this will probably be more useful in practice than composepic +compositions [] = [EMPTYPIC] +compositions (xx:etc) = f[apic1 x r // x <- xx; r <- compositions etc] + where + f [] = [] + f (FAIL:x) = f x + f (SUCCEED a:x) = a: f x +overlaypic :: [picture]->picture +||similar to the above but allows pictures earlier in the given list to hide +||details of later ones, so the result is always a picture +overlaypic = foldr opic EMPTYPIC +apic :: picture->query picture->query picture ||picture addition +p $apic SUCCEED EMPTYPIC = SUCCEED p +p $apic FAIL = FAIL +EMPTYPIC $apic q = q +MKPIC (x1,y1) a $apic SUCCEED (MKPIC (x2,y2) b) + = FAIL, if xx=FAIL + = SUCCEED (MKPIC (x,y) (f xx)), otherwise + where + x = min[x1,x2] + y = max[y1,y2] + xx = pointwiseadd a1 b1 + a1 = sidepad (x1-x) (-rjut) (toppad (y-y1) a) + b1 = sidepad (x2-x) rjut (toppad (y-y2) b) + rjut = x1+#a!0-x2-#b!0 + f(SUCCEED c) = c +apic1 :: picture->picture->query picture ||picture addition mark2 +p $apic1 EMPTYPIC = SUCCEED p +EMPTYPIC $apic1 q = SUCCEED q +MKPIC (x1,y1) a $apic1 MKPIC (x2,y2) b + = FAIL, if xx=FAIL + = SUCCEED (MKPIC (x,y) (f xx)), otherwise + where + x = min[x1,x2] + y = max[y1,y2] + xx = pointwiseadd a1 b1 + a1 = sidepad (x1-x) (-rjut) (toppad (y-y1) a) + b1 = sidepad (x2-x) rjut (toppad (y-y2) b) + rjut = x1+#a!0-x2-#b!0 + f(SUCCEED c) = c +opic :: picture->picture->picture ||picture superposition +p $opic EMPTYPIC = p +EMPTYPIC $opic q = q +MKPIC (x1,y1) a $opic MKPIC (x2,y2) b + = MKPIC (x,y) (pointwiseoverlay a1 b1) + where + x = min[x1,x2] + y = max[y1,y2] + a1 = sidepad (x1-x) (-rjut) (toppad (y-y1) a) + b1 = sidepad (x2-x) rjut (toppad (y-y2) b) + rjut = x1+#a!0-x2-#b!0 +sidepad n r a = [spaces n ++ p ++ spaces r | p <- a] +toppad n a = f n + where + f n = a, if n<=0 + = spaces (#a!0):f (n-1), otherwise +pointwiseoverlay :: [[char]]->[[char]]->[[char]] +pointwiseoverlay a b = f a b + where + f [] b = b + f a [] = a + f (p:a) (q:b) = g p q:f a b + g [] q = q + g p [] = p + g (c1:p) (c2:q) = c2:g p q, if c1=' ' + = c1:g p q, otherwise +pointwiseadd :: [[char]]->[[char]]->query [[char]] +pointwiseadd a b = SUCCEED c, if and [~member z clashchar | z<-c] + = FAIL, otherwise + where + c = f a b + f [] b = b + f a [] = a + f (p:a) (q:b) = g p q:f a b + g [] q = q + g p [] = p + g (c1:p) (c2:q) = c2:g p q, if c1=' ' + = c1:g p q, if c2=' ' + = clashchar:g p q, otherwise +clashchar = '\0' ||assumed not to be present in any normal picture +pic :: num->num->[[char]]->picture +||takes a rectangular array of chars and turns it into a picture with its north +||west corner at the given x y position +pic x y a = EMPTYPIC, if and[p=[]|p<-a] + ||covers both a=[] and elements a all [] + = pic x (y-1) (tl a), if and[c=' ' | c<-hd a] + ||strip blank rows + = pic (x+1) y (map tl a), if and[hd p=' ' | p <- a] + ||strip blank cols + = MKPIC (x,y) a, otherwise + ||what about east and south trimming? -- fix later +||we have assumed given a rectangular and not containing control chars, we +||ought perhaps to check this when a picture is formed -- fix later + +newlines n = rep n '\n' +closure :: (*->[*])->[*]->[*]; +||takes the closure of a set under a pointwise function that returns +||increments to the set +closure f s = g s s + where + g r t = [], if t=[] + = t ++ g(r ++ t)(mkset[x|x<-concat(map f t);~member r x]), + otherwise diff --git a/miralib/ex/hamming.m b/miralib/ex/hamming.m new file mode 100644 index 0000000..3ebb6ce --- /dev/null +++ b/miralib/ex/hamming.m @@ -0,0 +1,19 @@ +||this is a problem described by Dijkstra in his book, A Discipline of +||Programming, and attributed by him to Dr Hamming, of Bell Labs. +||Print in ascending order all numbers of the form +|| 2**a.3**b.5**c a,b,c all >=0 +||the solution here is based on a method using communicating processes. +||ham is the list of numbers, to see them, say +|| ham +||hit control-C (interrupt) when you have seen enough! + +ham = 1 : foldr1 merge [mult 2 ham, mult 3 ham, mult 5 ham] + where + mult n x = [n*a|a<-x] + merge (a:x) (b:y) = a : merge x y, if a=b + = a : merge x (b:y), if ab + +||Note that there is a function called `merge' in the standard +||environment, but unlike the one defined above it does not remove +||duplicates from the lists being merged. diff --git a/miralib/ex/hanoi.m b/miralib/ex/hanoi.m new file mode 100644 index 0000000..b927ca3 --- /dev/null +++ b/miralib/ex/hanoi.m @@ -0,0 +1,11 @@ +||This script generates a solution to the well known `Towers of Hanoi' +||problem. To see the moves (for a game with 12 discs) say +|| soln + +soln = title++hanoi 12 "A" "B" "C" +title = "SOLUTION TO TOWERS OF HANOI WITH 8 DISCS\n\n" +hanoi 0 a b c = [] +hanoi (n+1) a b c = hanoi n a c b + ++ move a b ++ + hanoi n c b a +move a b = "move the top disc from "++a++" to "++b++"\n" diff --git a/miralib/ex/just.m b/miralib/ex/just.m new file mode 100644 index 0000000..9dca373 --- /dev/null +++ b/miralib/ex/just.m @@ -0,0 +1,98 @@ +||Text formatting program (DT) +||Reformats text to a specified width, with line-fill + +%export just + +||To try this out from within a Miranda session, say e.g. +|| just 60 (read "file") +||where "file" contains some text you want to reformat. + +||You could also make it into a UNIX filter -- see the example `mrev'. + +||----------------------------------------------------------------------|| +|| in this program we move between three different representations of || +|| text - as a flat list of characters, including spaces and newlines || +|| - as a list of lines (containing spaces but not newlines) || +|| - and as a list of list of words. || +||----------------------------------------------------------------------|| + +text == [char] +line == [char] +word == [char] + +just::num->text->text ||the main function +just n = concat.map(reformat n).paras.map words.lines + +||lines::text->[line] +||lines is defined in - it breaks a string into lines, +||removing the newline characters + +paras::[[word]]->[[word]] +||make each paragraph into one long line, by joining adjacent +||non-blank lines +paras (a:b:x) = paras ((a++b):x), if a~=[]~=b + = a:paras (b:x), otherwise +paras (a:[]) = a:[] +paras [] = [] + +reformat::num->[word]->text +||reformat a paragraph to width n +reformat n [] = "\n" ||the empty paragraph represents a blank line +reformat n x = lay(justify n (partition n x)) + +||lay::[line]->text +||lay is defined in - it is the inverse of lines + +justify::num->[[word]]->[line] +justify n para = map(fill_line n)(init para)++[unwords(last para)] + +partition::num->[word]->[[word]] +||break a paragraph into lines, with as many words as will fit in width +||n on each line (except the last) +partition n [] = [] +partition n x = x1 : partition n rest + where + (x1,rest) = grab [] x + grab y (w:x) = grab (w:y) x, if sum(map(#)y)+#y+#w <= n + = (reverse y,w:x), otherwise + grab y [] = (reverse y,[]) + +fill_line :: num->[word]->line +||make words into a line of length n exactly, by inserting enough spaces +fill_line n words + = (concat.concat) (transpose [words,mkspaces (w-1) (n-sw)]) + where + w = #words + sw = sum(map (#) words) + +mkspaces :: num->num->[[char]] +||return s spaces broken into n groups +mkspaces n s = map f [1..n], if n mod 2=0 ||see note + = map f [n,n-1..1], otherwise + where + f i = rep (s div n + delta) ' ' + where + delta = 1, if i<=s mod n + = 0, otherwise +||note: we put the extra spaces in sometimes from the left and sometimes +||from the right, depending on the parity of n. This is to avoid +||visually unbalancing the text by having all the extra spaces towards +||one margin. Using the parity of n to decide this is arbitrary. + +words :: line->[word] +||break a line into words +words = filter (~=[]) . foldr (breakon ' ') [[]] + +unwords :: [word]->line +||join words to make a line, inserting one space as separator +unwords = foldr1 (insert ' ') + +insert :: *->[*]->[*]->[*] +insert a x y = x ++ [a] ++ y + +breakon :: *->*->[[*]]->[[*]] +breakon c a x = []:x, if a=c + = (a:hd x):tl x, otherwise + +||These definitions of `words' and `unwords' are due to Richard Bird, see +||Bird and Wadler (1988), page 91. diff --git a/miralib/ex/kate.lit.m b/miralib/ex/kate.lit.m new file mode 100644 index 0000000..7deb3cc --- /dev/null +++ b/miralib/ex/kate.lit.m @@ -0,0 +1,138 @@ +\documentclass[10pt]{article} +\title{{\tt kate.lit.m} --- KaTify text} +\author{J. Cupitt} +\date{July 21st, 1989} +% turn off para indents +\setlength{\parindent}{0in} +% put some space between paras +\setlength{\parskip}{0.05in} +\begin{document} +\maketitle + +%An example of a Miranda literate script that is also a LaTeX source +%file. Note that the lines of formal program text are surrounded by +%LaTeX verbatim directives. Contributed by John Cupitt, of the +%University of Kent. + +There is a group on USENET called \verb"rec.music.gaffa", dedicated to the +singer Kate Bush. A running joke in this group is to pretend fanatical +devotion to Kate And Her Works --- this reaches an extreme form in some +posters, who capitalise all the Ks and Ts in their articles in reference both +to KaTe herself and to the Knights Templar. This Miranda\footnote{Miranda is a +trademark of Research Software Ltd.} script can be used as a {\sc +Unix}\footnote{UNIX is a trademark of AT\&T in the USA and other +countries.} filter to prepare your articles for posting to \verb"gaffa". +The main function is called \verb"kate" and is at the end. + +Do some simple maps on text. We do: + +\begin{center} +\begin{tabular}{rcl} + c,C,k & $\rightarrow $ & K \\ + t & $\rightarrow $ & T \\ + qu,Qu & $\rightarrow $ & Kw \\ + ck & $\rightarrow $ & K \\ + ch,Ch & $\rightarrow $ & Khe +\end{tabular} +\end{center} + +We also look for Kommon words that can be easily swapped for something with +more ks and ts. + +The dictionary we use to look for common words. This is very small at the +moment! I should perhaps find a thesaurus and fix this up properly. + +\begin{verbatim} + +> kateMap +> = [(["interpose", "insert"], +> "interject"), +> (["frequent", "general", "usual", "normal"], +> "common"), +> (["program", "file"], +> "script"), +> (["name"], +> "appelation"), +> (["however"], +> "though"), +> (["serve"], +> "officiate"), +> (["intersperse"], +> "punctuate") +> ] + +\end{verbatim} + +First map. Very easy! + +\begin{verbatim} + +> swapCase :: [char] -> [char] +> swapCase ('c':'k':x) = 'K':swapCase x +> swapCase ('c':'h':x) = 'K':'h':'e':swapCase x +> swapCase ('C':'h':x) = 'K':'h':'e':swapCase x +> swapCase ('c':x) = 'K':swapCase x +> swapCase ('C':x) = 'K':swapCase x +> swapCase ('k':x) = 'K':swapCase x +> swapCase ('t':x) = 'T':swapCase x +> swapCase ('q':'u':x) = 'K':'w':swapCase x +> swapCase ('Q':'u':x) = 'K':'w':swapCase x +> swapCase (a:x) = a: swapCase x +> swapCase [] = [] + +\end{verbatim} + +Second map. We loop down the input again, chopping out words. Each one gets +put through tryMap. + +\begin{verbatim} + +> swapWords :: [char] -> [char] +> swapWords [] = [] +> swapWords inp +> = punk ++ tryMap word ++ swapWords tail +> where +> punk = takewhile ((~) . letter) inp +> start = dropwhile ((~) . letter) inp +> word = takewhile letter start +> tail = dropwhile letter start + +\end{verbatim} + +Try to map a word through the KaTe thesaurus we defined earlier. We try to be +clever about what we swap. For example, we want \verb"insert" to be mapped to +\verb"interject", and \verb"inserting" to be mapped to \verb"interjecting". +This isn't always the most sensible way to do it \ldots + +\begin{verbatim} + +> tryMap :: [char] -> [char] +> tryMap word +> = word, if maps = [] +> = hd maps, otherwise +> where +> maps = [ to ++ drop (#x) word | +> (from, to) <- kateMap; x <- from; +> x $isprefix word ] + +\end{verbatim} + +Test for first argument a prefix of the second argument. + +\begin{verbatim} + +> isprefix :: [*] -> [*] -> bool +> isprefix a b = take (#a) b = a + +\end{verbatim} + +And our entry point. We just pipe stuff first through swapWords, then through +swapCase. + +\begin{verbatim} + +> kate :: [char] -> [char] +> kate = swapCase . swapWords + +\end{verbatim} +\end{document} diff --git a/miralib/ex/kate.pdf b/miralib/ex/kate.pdf new file mode 100644 index 0000000..606a4c8 Binary files /dev/null and b/miralib/ex/kate.pdf differ diff --git a/miralib/ex/kate.tex b/miralib/ex/kate.tex new file mode 120000 index 0000000..8da0f90 --- /dev/null +++ b/miralib/ex/kate.tex @@ -0,0 +1 @@ +kate.lit.m \ No newline at end of file diff --git a/miralib/ex/keith.m b/miralib/ex/keith.m new file mode 100644 index 0000000..b743de9 --- /dev/null +++ b/miralib/ex/keith.m @@ -0,0 +1,31 @@ +> ||this tests that floating point overflow is handled correctly + +Date: Mon, 16 Apr 90 17:15:03 CST +From: mccrosky@ishmael.usask.ca + +Sorry for the delay in sending my bignum problem, I've been out of town. + +> keith n = (shownum n) ++ " " ++ (shownum ((log (sumterm n))/n)) where +> sumterm n = sum (map prodterm [0..entier (n/2)]) where +> prodterm p = prod (map term [0..p-1]) where +> term j = x*(x-1)/((p-j)^2) where +> x = n-(2*j) +> prod = foldr (*) 1 +> lim = lay (from 1) where from n = (keith n):(from (n*2)) + + +******** This is the execution: + (We believe the results up to n=256 are correct). + +Miranda lim +1 0.0 +2 0.549306144334 +4 0.736109744792 +8 0.876176116589 +16 0.966470019952 +32 1.021895160467 +64 1.054884461071 +128 1.07405223475 +256 1.084981322415 +512 +should trap floating point overflow here diff --git a/miralib/ex/makebug.m b/miralib/ex/makebug.m new file mode 100644 index 0000000..b32d4bb --- /dev/null +++ b/miralib/ex/makebug.m @@ -0,0 +1,18 @@ +> makebug size = [Tofile "/tmp/big.m" (big_def size)] +> big_def n = "big_list\n=[\n" ++ lay (rep n " \"hello\",") ++ " \"hello\"]\n" + +This tests garbage collection during compilation. First turn on gc +reports by saying + /gc + +To generate /tmp/big.m of chosen size say, e.g. + makebug 10000 +to get mira to compile the result say + /f /tmp/big +Saying this repeatedly (or /f %) will force recompilations +Or from the command line after quitting mira + rm /tmp/big.x #to force recompilation + mira -make -gc /tmp/big + +If the heap becomes corrupted you will see strange type errors or +"impossible event" messages. From Rick Morgan at Durham, May 1990. diff --git a/miralib/ex/matrix.m b/miralib/ex/matrix.m new file mode 100644 index 0000000..46abbaf --- /dev/null +++ b/miralib/ex/matrix.m @@ -0,0 +1,70 @@ +||very simple matrix package (DT) +||note that to include this in one of your own scripts, you can say +|| %include + +%export matrix idmat matadd matsub matmult scalmult mkrow mkcol det + adjoint inv + +matrix == [[num]] + +idmat :: num->matrix ||identity matrix of given size +idmat n = [[delta i j|j<-[1..n]]|i<-[1..n]] + where + delta i j = 1, if i=j + = 0, otherwise + +matadd :: matrix->matrix->matrix +matadd x y = map2 vadd x y + where + vadd x y = map2 (+) x y + +matsub :: matrix->matrix->matrix +matsub x y = map2 vsub x y + where + vsub = map2 (-) + +matmult :: matrix->matrix->matrix +matmult x y = outer inner x (transpose y) ||* +inner x y = sum (map2 (*) x y) +outer f x y = [[f a b|b<-y]|a<-x] + +||*note that transpose is already defined in the standard environment + +scalmult :: num->matrix->matrix ||multiply a matrix by a scalar +scalmult n x = map (map (*n)) x + +mkrow :: [num]->matrix ||make vector into matrix with a single row +mkrow x = [x] + +mkcol :: [num]->matrix ||make vector into matrix with a single column +mkcol x = map (:[]) x + +det :: matrix->num ||determinant, of square matrix +det [[a]] = a +det xs = sum [xs!0!i*cofactor 0 i xs|i<-index xs], if #xs=#xs!0 + = error "det of nonsquare matrix", otherwise +cofactor i j xs = (-1)^(i+j) * det (minor i j xs) +minor i j xs = [omit j x | x<-omit i xs] +omit i x = take i x ++ drop (i+1) x + +adjoint :: matrix->matrix ||adjoint, of square matrix +adjoint xs = transpose[[cofactor i j xs | j<-index xs] | i <- index xs] + +inv :: matrix->matrix ||inverse, of non-singular square matrix +inv xs = transpose[[cofactor i j xs/h | j<-index xs] | i <- index xs] + where + h = det xs +||The above is a literal transcription of the mathematical definition of +||matrix inverse. A less naive version of the package would rewrite +||this to use Gaussian elimination. + +||a few test matrices (these are not exported from the script, but will +||be in scope if this is your current script) +a = [[1,2],[3,4]] +b = [[1,1,1],[1,2,3],[2,4,8]] +c = [[0,1,2,3],[1,2,3,4],[2,3,4,0],[3,4,0,1]] +i2 = idmat 2 +i3 = idmat 3 +i4 = idmat 4 + +test = matmult b (inv b) diff --git a/miralib/ex/mrev b/miralib/ex/mrev new file mode 100755 index 0000000..85b3dc6 --- /dev/null +++ b/miralib/ex/mrev @@ -0,0 +1,22 @@ +#! /usr/bin/mira -exec +main :: [sys_message] +main = map f (tl $*), if # $* > 1 ||$* is equivalent to argv + = [Stdout (revlines $-)], otherwise ||no files, use stdin ($-) + +f :: [char]->sys_message +f fil = Stderr ("mrev: cannot open "++fil++"\n"), if badfile + = Stdout (revlines (read fil)), otherwise + where + badfile = ~ member (filemode fil) 'r' + +revlines :: [char]->[char] +revlines = lay.map reverse.lines + +||The usage of this command (from a UNIX shell) is +|| mrev [file] ... +||If no files given, takes data from stdin. This is a Miranda version +||of the UNIX command `rev' which reverses each line of its input. + +||This example is a template for turning any Miranda function of type +||[char]->[char] into a UNIX filter. Replace `revlines' in the above +||text, by your chosen function. diff --git a/miralib/ex/parafs.m b/miralib/ex/parafs.m new file mode 100644 index 0000000..be6af05 --- /dev/null +++ b/miralib/ex/parafs.m @@ -0,0 +1,33 @@ +||program for printing isomers of the alkanes -- D.A.Turner +||say `output' to run +mol ::= H | C[mol] ||new type -- alkane molecules and radicals +c p = C (sort p) ||place subcomponents in a standard order +molecules n = mkset [ mk_molecule x | x <- radicals n ] +mk_molecule(C p) = canonical_orientation (C(H:p)) +radicals 0 = [H] +radicals n = (map rads [1..])!(n-1) || make rads a memo function +rads n = mkset [ c[x,y,z] | i <- [0..(n-1)div 3]; j <- [i..(n-1-i)div 2]; + x <- radicals i; y <- radicals j; z <- radicals(n-1-i-j) ] +canonical_orientation x = min (closure reorientations [x]) +reorientations (C p) = [ invert (p--[x]) x | x <- p; x ~= H ] + where + invert p (C q) = c (c p:q) +output = concat (map out [1..]) +out n = title n ++ concat(map prettyprint (molecules n)) +title n = "isomers of " ++ prefix!(n-1) ++ "ane\n" +prefix = ["meth","eth","prop","but","pent","hex","hept","oct","non", + "dec"] ++ [show i++"-"|i<-[11..]] + +||below this line is concerned with drawing pictures of the molecules +%include "graphics.m" +prettyprint x = printpic1 (hd (molpics x)) ++ "\n" +molpics (C p) = compositions ([centre]:map f [1..# p] ) + where + f i = map (reflect (direction!(i-1))) (subpics i) + subpics i = [q1|q<-molpics (p!(i-1)); + q1<-shift(translate 1 0 q),shift q1..] +molpics H = [pic 0 0 ["H"]] +direction = [1,-1,0,2] +shift p = translate 1 0 (overlaypic[bond,p]) +bond = pic 0 0 ["-"] +centre = pic 0 0 ["C"] diff --git a/miralib/ex/polish.m b/miralib/ex/polish.m new file mode 100644 index 0000000..21e58a5 --- /dev/null +++ b/miralib/ex/polish.m @@ -0,0 +1,34 @@ +||very simple testbed for Miranda unification package, "unify.m" + +||The expressions to be unified here are strings written in (forward) +||polish notation, such as "*+12-xy" - meaning (1+2)*(x-y). The +||operators are + - * / with single letter variables, and single digit +||constants. We provide bindings for the free identifiers of "unify.m" +||corresponding to this syntax. + +%include "unify.m" + { expr==[char]; operator==char; var==char; + isvar=isvar; getvar=getvar; putvar=putvar; + rator=rator; rands=rands; construct=construct; + } + +isvar e = letter (hd e) +getvar = hd +putvar = (:[]) +rator = hd +rands (c:[]) = [], if digit c +rands (c:e) = [a,b], if member "+-*/" c & e2=[] + = error "illegal string", otherwise + where + (a,e1) = get e + (b,e2) = get e1 + get [] = error "illegal string" + get (c:x) = ([c],x), if letter c \/ digit c + = ([c]++a++b,x2), otherwise + where + (a,x1) = get x + (b,x2) = get x1 +construct c xs = c:concat xs + +test = unifyexprs "*+x3/7x" "*+1y/z1" ||the result should be "*+13/71" +test1 = unifyexprs "*+x3/7x" "*+1y/y1" ||not unifiable diff --git a/miralib/ex/powers.m b/miralib/ex/powers.m new file mode 100644 index 0000000..019a139 --- /dev/null +++ b/miralib/ex/powers.m @@ -0,0 +1,15 @@ +||prints a table of powers 2 to 5 of the numbers 1 to 20 +||to see the table, say +|| output + +output = title ++ captions ++ concat (map line [1..20]) + +title = cjustify 60 "A TABLE OF POWERS" ++ "\n\n" + +captions = format "N" ++ concat (map caption [2..5]) ++ "\n" + +caption i = format ("N^" ++ shownum i) + +format = rjustify 12 + +line n = concat [format (show(n^i)) | i<-[1..5]] ++ "\n" diff --git a/miralib/ex/primes.m b/miralib/ex/primes.m new file mode 100644 index 0000000..2a7c5df --- /dev/null +++ b/miralib/ex/primes.m @@ -0,0 +1,7 @@ +||The infinite list of all prime numbers, by the sieve of Eratosthenes. +||To see the list, just say `primes', or if you prefer +|| lay(map show primes) +||will print them one per line. Hit control-C (interrupt) to stop. + +primes = sieve[2..] +sieve (p:x) = p:sieve[n|n<-x;n mod p~=0] diff --git a/miralib/ex/pyths.m b/miralib/ex/pyths.m new file mode 100644 index 0000000..8301e47 --- /dev/null +++ b/miralib/ex/pyths.m @@ -0,0 +1,9 @@ +||Finds all pythagorean triangles (right triangles with integer sides) +||Note the use of a diagonalising list comprehension, with `//' instead +||of `|'. To see the triangles, say +|| output + +output = lay (map show pyths) +pyths = [(a, b, intsqrt (a*a+b*b)) // a <- [3..]; b<-[a+1..]; is_sq (a*a+b*b)] +intsqrt x = entier (sqrt x) +is_sq y = (intsqrt y) ^ 2 = y diff --git a/miralib/ex/queens.m b/miralib/ex/queens.m new file mode 100644 index 0000000..2ed5734 --- /dev/null +++ b/miralib/ex/queens.m @@ -0,0 +1,22 @@ +||this generates all solutions to the 8 queens problem -- say +|| solns +||and it will print the solutions one per line - all 92 of them. This +||is a good program for testing the garbage collector. Say `/gc' to +||switch on garbage collector diagnostics. + +solns = layn(map show (queens 8)) +queens 0 = [[]] +queens (n+1) = [q:b|b<-queens n;q<-[1..8];safe q b] +safe q b = and[~checks q b i|i<-index b] +checks q b i = q=b!i \/ abs(q-b!i)=i+1 + +||Note that the function `queens n' returns a list of all solutions to +||the n queens problem (placing queens in the first n columns of a chess +||board, so that no queen gives check to another). A board with n +||queens is represented as a list of n numbers, namely the positions of +||the queens in each column + +||This example exhibits a basic technique of lazy functional +||programming, which is to eliminate backtracking from a search problem +||by working at the level of a list of all solutions, rather than a +||single solution. diff --git a/miralib/ex/queens1.m b/miralib/ex/queens1.m new file mode 100644 index 0000000..79b52a8 --- /dev/null +++ b/miralib/ex/queens1.m @@ -0,0 +1,16 @@ +||This finds one solution to the eight queens problem, using a +||different method from that of the previous script, "queens.m". +||To run it, say +|| output +||This time the backtracking is programmed explicitly + +output = concat [c:shownum r++" "|(c,r)<-zip2 "rnbqkbnr" soln] +soln = until full extend emptyboard +extend board = until safe alter (addqueen board) +addqueen board = 1:board +emptyboard = [] +full board = # board=8 +alter (q:board) = q+1:board, if q<8 + = alter board, otherwise ||backtrack +safe (q:board) = and [~checks q board i|i<-index board] +checks q board i = q=board!i \/ abs(q-board!i)=i+1 diff --git a/miralib/ex/quicksort.m b/miralib/ex/quicksort.m new file mode 100644 index 0000000..2da7d55 --- /dev/null +++ b/miralib/ex/quicksort.m @@ -0,0 +1,12 @@ +||this is a functional version of quicksort, to see it work, say: +|| qsort testdata +||the reason we have to call the function `qsort' rather than `sort' is +||because there is a `sort' already defined in the standard environment + +qsort [] = [] +qsort (a:x) = qsort [b|b<-x;b<=a] ++ [a] ++ qsort[b|b<-x;b>a] + +testdata = f 10 +f n = concat(transpose [[0,2..2*n],[2*n-1,2*n-3..1]]) + +||note that the sort included in the standard environment is merge-sort diff --git a/miralib/ex/rational.m b/miralib/ex/rational.m new file mode 100644 index 0000000..8b432d1 --- /dev/null +++ b/miralib/ex/rational.m @@ -0,0 +1,56 @@ +||rational numbers as an abstract data type, say +|| %include +||to include this in one of your own scripts. Quoting the filename in +||this form makes the %include directive work from any directory. + +abstype rational +with ratio :: num -> num -> rational + mkrat :: num->rational + rplus, rminus, rtimes, rdiv :: rational -> rational -> rational + rpow :: num -> rational -> rational + numerator, denominator :: rational -> num + rparts :: rational -> (num,num) + showrational :: rational -> [char] + +rational == (num,num) + +||a rational is represented as a pair of integers +||note that rationals are kept in their lowest terms, with positive +||denominator, and (0,1) is the unique representation of zero + +ratio p q = error "illegal ratio", if q=0\/~integer p\/~integer q + = ratio (-p) (-q), if q<0 + = (0,1), if p=0 + = (p div h,q div h), otherwise + where + h = hcf (abs p) q + hcf a b = hcf b a, if a>b + = b, if a=0 + = hcf (b mod a) a, otherwise + +mkrat n = ratio n 1, if integer n + = error ("mkrat "++shownum n), otherwise + +(a,b) $rplus (c,d) = ratio (a*d+c*b) (b*d) +(a,b) $rminus (c,d) = ratio (a*d-c*b) (b*d) +(a,b) $rtimes (c,d) = ratio (a*c) (b*d) +(a,b) $rdiv (c,d) = ratio (a*d) (b*c) + +rpow 0 x = (1,1) +rpow n x = thing, if n mod 2 = 0 + = x $rtimes thing, otherwise + where + thing = rpow (n div 2) (x $rtimes x) + +numerator = fst +denominator = snd +rparts = id + +showrational (a,b) = "(ratio "++shownum1 a++" "++shownum1 b++")" +shownum1 n = "("++shownum n++")", if n<0 + = shownum n, otherwise + +||Attempts to print a rational will automatically pick up the function +||called showrational - see manual section on abstract data types. Note +||that we have chosen to print rationals in such a way that Miranda can +||read them back in again at the same type. diff --git a/miralib/ex/refoliate.m b/miralib/ex/refoliate.m new file mode 100644 index 0000000..028f362 --- /dev/null +++ b/miralib/ex/refoliate.m @@ -0,0 +1,60 @@ +> tree ::= Leaf num | Fork tree tree + +PROBLEM: write down the definition of a function which takes a tree and +returns a tree of the SAME SHAPE, containing the same data, but with the +leaves moved around so that the data appears in ascending order, when +the tree is scanned from left to right. + +> reorder :: tree->tree +> reorder t = refoliate t (sort (fringe t)) + +Our idea here is that `fringe' extracts a list of all the data in the +tree, while `refoliate' takes a tree and a list of data, and replaces +the leaves of the tree with the given data, preserving the shape of the +tree. We define fringe first, as it is the easiest. + +> fringe :: tree->[num] +> fringe (Leaf n) = [n] +> fringe (Fork s t) = fringe s ++ fringe t + +Aside - there is a trivial change to the last line which alters the +behaviour of fringe so that the call to sort is no longer necessary. We +can replace `++' by a call to the library function `merge'. This would +improve the efficiency of the solution. + +We define `refoliate' in terms of an auxiliary function which takes a +subtree and the list of replacement data, and returns a pair - the +refoliated subtree, and the unused part of the list. + +> refoliate :: tree->[num]->tree +> refoliate t x = fst (refol t x) + +> refol :: tree->[num]->(tree,[num]) +> refol (Leaf n) (a:x) = (Leaf a,x) +> refol (Fork s t) x = (Fork s1 t1,x'') +> where +> (s1,x') = refol s x +> (t1,x'') = refol t x' + +Here is an example tree on which to call `reorder', to see that the +algorithm works. + +> t1 = mktree [19,0,17,2,15,4,13,6,11,8,9,10,7,12,5,14,3,16,1,18] + +mktree takes a list and builds a (well-balanced) tree from it. + +> mktree :: [num]->tree +> mktree [] = error "cannot have empty tree" +> mktree [a] = Leaf a +> mktree x = Fork (mktree (take n x)) (mktree (drop n x)) +> where n = # x div 2 + +Finally, we define a function same_shape, which can be used to confirm +that reorder holds the shape constant. + +> same_shape :: tree->tree->bool +> same_shape (Leaf a) (Leaf b) = True +> same_shape (Fork s t) (Fork s1 t1) = same_shape s s1 & same_shape t t1 +> same_shape s t = False ||all other cases + +> test = same_shape t1 (reorder t1) diff --git a/miralib/ex/selflines.m b/miralib/ex/selflines.m new file mode 100644 index 0000000..cf3d016 --- /dev/null +++ b/miralib/ex/selflines.m @@ -0,0 +1,32 @@ +||this produces an endless self describing scroll of lines, as follows +|| the 1st line is +|| "the 1st line is" +|| the 2nd line is +|| ""the 1st line is"" +|| the 3rd line is +|| "the 2nd line is" +|| etc... +||To see the result, say +|| output +||Hit control-C (interrupt) when you have seen enough. +||If you would like to send the output to a file, say +|| output &> fil +||where `fil' is the name of the file in which you want to put it +||this will create a background job + +output = concat[l++"\n"|l<-selflines] + +selflines = mklines 1 + +mklines n = ("the "++ord n++" line is:"): + ("\""++selflines!(n-1)++"\""): + mklines(n+1) + +ord n = show n++suffix n + +suffix 1 = "st" +suffix 2 = "nd" +suffix 3 = "rd" +suffix n = "th", if n=0 \/ 3<=n&n<=9 + = "th", if (n mod 100)div 10 = 1 ||because of 11,12,13 + = suffix(n mod 10), otherwise diff --git a/miralib/ex/set.m b/miralib/ex/set.m new file mode 100644 index 0000000..c6a52f9 --- /dev/null +++ b/miralib/ex/set.m @@ -0,0 +1,64 @@ +||definition of finite sets as an abstract data type, say +|| %include +||to include this in one of your own scripts. + +abstype set * +with makeset::[*]->set * ||converts list to set + enum::set *->[*] ||converts set to list + empty::set * ||empty set + mem::set *->*->bool ||does set contain element? + pincludes,includes::set *->set *->bool ||(proper) set inclusion + union::[set *]->set * ||union of a list of sets + intersect::[set *]->set * ||intersection of a list of sets + setdiff::set *->set *->set * ||set difference of two sets + union2::set *->set *->set * ||union of two sets + intersect2::set *->set *->set * ||intersection of two sets + add1::*->set *->set * ||add a single element to a set + sub1::*->set *->set * ||remove an element from a set (if present) + pick::set *->* ||pick some element from a set + rest::set *->set * ||remainder of set, without element got by pick + showset::(*->[char])->set *->[char] ||to make sets printable + +set * == [*] ||a set is represented as a list without duplicates +makeset = uniq.sort ||for efficiency the lists are kept sorted +enum = id +empty = [] +mem (a:x) b = a=b \/ ab + = setdiff x y, otherwise +setdiff x y = x +intersect2 (a:x) (b:y) = intersect2 x (b:y), if ab + = a : intersect2 x y, otherwise +intersect2 x y = [] +intersect = foldl1 intersect2 +add1 a (b:x) = a:b:x, if a[*] +uniq (a:b:x) = uniq (a:x), if a=b + = a:uniq (b:x), otherwise +uniq x = x diff --git a/miralib/ex/stack.m b/miralib/ex/stack.m new file mode 100644 index 0000000..d7a1af2 --- /dev/null +++ b/miralib/ex/stack.m @@ -0,0 +1,19 @@ +||This script defines stack, as an abstract data type based on lists. +||Note that there is a show function for stacks, causing them to print +||in a sensible way. + +abstype stack * +with empty::stack *; push::*->stack *->stack *; + pop::stack *->stack *; top::stack *->*; isempty::stack *->bool; + showstack::(*->[char])->stack *->[char] + +stack * == [*] +empty = [] +push a x = a:x +pop(a:x) = x +top(a:x) = a +isempty x = (x=[]) +showstack f [] = "empty" +showstack f (a:x) = "(push " ++ f a ++ " " ++ showstack f x ++ ")" + +teststack = push 1(push 2(push 3 empty)) diff --git a/miralib/ex/topsort.m b/miralib/ex/topsort.m new file mode 100644 index 0000000..88e96ee --- /dev/null +++ b/miralib/ex/topsort.m @@ -0,0 +1,32 @@ +||Miranda programming example - topological sort +topsort :: [(*,*)] -> [*] + +||topsort takes a list of pairs representing a partial order - where +||the presence of (u,v) in the list means that u precedes v in the +||ordering - and returns a total ordering consistent with the +||information given - that is if (u,v) is in the input data, then u will +||come before v in the output list. + +topsort rel = tsort (carrier rel) rel +||the carrier of a relation is the set of all the elements related by it + +tsort c r = [], if c=[] + = error "inconsistent data for tsort", if m=[] + = a : tsort (c--[a]) [(u,v)|(u,v)<-r; u~=a], otherwise + where + a = hd m + m = (c -- ran r) +||remarks on the above +|| - it is an invariant that c contains the carrier of relation r +|| - m is the set of elements of c with no predecessor in r + +||the error case will arise if the input data contains a cycle - i.e. +||if there is an element that directly or indirectly precedes itself. + +||a set is here represented as a list without duplicates +||the standard function mkset removes duplicates from a list + +dom r = mkset [u|(u,v)<-r] ||domain of a relation +ran r = mkset [v|(u,v)<-r] ||range of a relation +carrier r = union (dom r) (ran r) +union x y = mkset (x++y) diff --git a/miralib/ex/treesort.m b/miralib/ex/treesort.m new file mode 100644 index 0000000..e5b946b --- /dev/null +++ b/miralib/ex/treesort.m @@ -0,0 +1,20 @@ +|| Here is another sorting algorithm, this time treesort. +|| to try it out, say: treesort testdata + +tree * ::= NILT | NODE * (tree *) (tree *) + +treesort = flatten.build + +build::[*]->tree * +build = foldr insert NILT + +insert b NILT = NODE b NILT NILT +insert b (NODE a x y) = NODE a (insert b x) y, if b<=a + = NODE a x (insert b y), if b>a + +flatten::tree *->[*] +flatten NILT = [] +flatten (NODE a x y) = flatten x ++ [a] ++ flatten y + +testdata = [1..5]++[20,19..16]++[6..10]++[15,14..11] + diff --git a/miralib/ex/unify.m b/miralib/ex/unify.m new file mode 100644 index 0000000..1ce4034 --- /dev/null +++ b/miralib/ex/unify.m @@ -0,0 +1,79 @@ +||Package for doing (first order) unification, parameterised on an +||abstract theory of expressions. (DT) + +||see the file for an example of the use of this package. + +%free { expr,operator,var::type; + isvar::expr->bool; getvar::expr->var; putvar::var->expr; + rator::expr->operator; rands::expr->[expr]; + construct::operator->[expr]->expr; + } + +||Our theory of expressions is as follows - an expression is either a +||variable, or else it consists of a rator together with a list of +||rands. So for example a constant will be viewed as a rator which has +||an empty list of rands. The nature of variables, and the collection +||of possible rators and their arities, is determined at %include time. +||This enables us to use the same code for performing unification in +||quite different object languages. + +||for each e::expr, one of the following propositions will be true +||either isvar e & e = putvar(getvar e) +||or ~isvar e & e = construct(rator e)(rands e) + +%export unifyexprs unify ult q + +q * ::= FAIL | SUCCEED * ||useful type operator + +unifyexprs :: expr->expr->q expr ||convenient for testing + +unify :: subst->expr->expr->q subst + +||this implements the unification algorithm - it takes a substition +||(mapping from variables to expressions) and a pair of expressions, and +||returns the least extension of the substitution under which the +||expressions become the same - or FAIL if there is none. + +ult :: subst->expr->expr + +||computes the result of applying a substitution to an expression. + +unifyexprs x y = f(unify [] x y) + where + f FAIL = FAIL + f (SUCCEED s) = SUCCEED (ult s x) + ||note that (ult s y) = (ult s y) + ||if the unification succeeds + +subst == [(var,expr)] + +||We represent a substitution as a list of variable-expression pairs. +||The representation is lazy, in the sense that the expressions may +||contain occurrences of the variables in the domain of the substitution +||- this is taken care of in the definition of ult. + +unify s x y + = unifier s (ult s x) (ult s y) + where + unifier s x y = SUCCEED s, if x=y + = SUCCEED((getvar x,y):s), if isvar x & ~occurs x y + = SUCCEED((getvar y,x):s), if isvar y & ~occurs y x + = unifylist (SUCCEED s) (rands x) (rands y), + if ~isvar x & ~isvar y & conforms x y + = FAIL, otherwise + unifylist qs [] [] = qs + unifylist (SUCCEED s) (a:x) (b:y) = unifylist (unify s a b) x y + unifylist FAIL x y = FAIL + +ult s x = lookup s (getvar x), if isvar x + = construct(rator x)(map (ult s) (rands x)), otherwise + where + lookup [] a = putvar a + lookup ((a,y):t) a = ult s y ||note recursive call of ult + lookup ((b,y):t) a = lookup t a + +occurs y x || does subexpression y occur in formula x ? + = x=y, if isvar x + = or (map (occurs y) (rands x)), otherwise + +conforms x y = rator x = rator y & #rands x = #rands y diff --git a/miralib/helpfile b/miralib/helpfile new file mode 100644 index 0000000..9d28360 --- /dev/null +++ b/miralib/helpfile @@ -0,0 +1,25 @@ +SUMMARY OF MAIN AVAILABLE COMMANDS: + +exp evaluate a Miranda expression +exp &> file send value of expression to file (background process) +exp &>> file append value of expression to file (background process) +exp :: print type of exp +? list all identifiers in scope (grouped by source file) +?identifier(s) give more information about identifier(s) +??identifier open source file at definition of identifier +!command execute any UNIX shell command +!! repeat last shell command +/edit /e edit current script (default editor = vi or joe) +/edit filename edit filename +/file /f display filename of current script +/file filename change to new current script +/help /h display this command summary +/man /m ENTER ONLINE REFERENCE MANUAL (menu driven) +/quit /q quit the Miranda system +/aux /a display list of auxiliary commands + +Notes:- +each "/" command can be abbreviated to its first letter - /e /f /h /m /q +% is shorthand for the name of the current script (in commands) +Special case - note that `/f %' forces recompilation of current script +$$ is shorthand for the last expression evaluated (in expressions) diff --git a/miralib/manual/.epoch b/miralib/manual/.epoch new file mode 100644 index 0000000..01eee68 --- /dev/null +++ b/miralib/manual/.epoch @@ -0,0 +1 @@ +manual pages last revised 31 January 2020 diff --git a/miralib/manual/1 b/miralib/manual/1 new file mode 100644 index 0000000..d3eff94 --- /dev/null +++ b/miralib/manual/1 @@ -0,0 +1,76 @@ +_H_o_w_ _t_o_ _u_s_e_ _t_h_e_ _M_i_r_a_n_d_a_ _o_n_-_l_i_n_e_ _r_e_f_e_r_e_n_c_e_ _m_a_n_u_a_l: + +The manual is menu driven, and is a separate subsystem that can be +invoked from the Miranda command interpreter. To access the manual from +Miranda, type + /man +followed by return. To access the manual directly from the command +line, without entering Miranda first, type the line + mira -man +as a shell command. + +On entering the manual system a contents page is displayed listing +numbered sections. In response to the question at the bottom of the +page you should enter the number of the section you wish to see and +press return (i.e. ENTER). The contents of that section are then +displayed to you. When you are ready to leave the manual, press return, +without giving ay section number, in response to the question at the +foot of the contents page - typing q (for "quit") has the same effect. + +If the section is more than one page long, you should press the space +bar when you have finished reading a page, in order to see the next page +(or press return to see one more line). At the end of the section, you +may press return to go back to the contents page. + +The manual is organised in short sections, each at most two or three +screenfulls long. Where a section would otherwise be too long to fit in +with this philosophy, the manual is organised recursively and will +display a subsidiary contents page, with a list of numbered subsections, +which you may read, as before, by typing the appropriate number. To +return to the main menu from a submenu, press return with no section +number, in response to the question at the bottom of the page. + +The manual is intended to provide online documentation of the Miranda +programming language and the command system in which it is embedded. It +is not intended to be a tutorial on functional programming. It does not +provide information about the operating system, for which separate +documentation is available (but there is a section on the Miranda/UNIX +interface). + +------------------------------------------------------------------------ +_S_u_m_m_a_r_y_ _o_f_ _m_a_n_u_a_l_ _b_e_h_a_v_i_o_u_r_: + +Whenever the manual system prompts the user for input - by asking for +"next selection" - the complete repertoire of possible responses is: + +q quit the manual + exit one level of menu structure + (i.e. if at foot of section, return to menu + if at submenu, return to master menu + if at main menu, quit the manual) + display section from current contents page +. (dot) same again, i.e. redisplay last requested section ++ display next section in numerical order +- display previous section +!command temporary escape to O/S, executes shell command + +------------------------------------------------------------------------ +_S_u_m_m_a_r_y_ _o_f_ _t_h_e_ _b_e_h_a_v_i_o_u_r_ _o_f_ _`_m_o_r_e_'_: + +Individual sections of the manual are displayed to you using the UNIX +program `more' or an equivalent such as `less' (you can change this by +setting an environment variable VIEWER (*)). These programs have their +own UNIX manual page describing their features. The responses you can +give generally include + +[SPACE] display next screenful +[return] display one more line +q (quit) cease showing me this file +b (back) scroll backwards by one screenful +/context search for context (eg a word) +?context search backwards for context +h help + +(*) See the section on Environment Variables under UNIX/Miranda system +interface. + diff --git a/miralib/manual/10 b/miralib/manual/10 new file mode 100644 index 0000000..d4d48b9 --- /dev/null +++ b/miralib/manual/10 @@ -0,0 +1,60 @@ +_I_d_e_n_t_i_f_i_e_r_s + +An identifier consists of a letter followed by zero or more additional +characters which may be letters digits or occurrences of _ or ' +(underscore and single quote) Examples: + x yellow p11d y' GROSS_INCOME +Note that both upper and lower case letters are allowed, and they are +treated as different, so x and X are not the same identifier. There is +no restriction on the length of identifiers, and all the characters are +significant in deciding whether two identifiers are the same. +Identifiers fall into two different classes (called in the formal syntax +`identifier' and `IDENTIFIER') depending on whether their initial letter +is upper or lower case. + +Identifiers are used for three different purposes in Miranda - (i) as +variables, i.e. names for values (note that the names of functions are +also considered to be variables), (ii) as typenames, such as `bool' and +`char', and (iii) as constructors (see section on algebraic types). The +names of constructors must begin with an upper case letter, while +variables and typenames must begin with a lower case letter. + +Reserved words - the following are special symbols of the Miranda +language. + +_a_b_s_t_y_p_e _d_i_v _i_f _m_o_d _o_t_h_e_r_w_i_s_e _r_e_a_d_v_a_l_s _s_h_o_w _t_y_p_e _w_h_e_r_e _w_i_t_h + (10) + +These are often shown as underlined (or bold) in published documents, +but in programs they are typed as ordinary lower case words (which means +that these words cannot be used as identifiers). + +_P_r_e_d_e_f_i_n_e_d_ _i_d_e_n_t_i_f_i_e_r_s + +The following identifiers are normally* predefined and always in scope. +They constitute the `standard environment'. They are defined in the +script "stdenv.m", contained in the directory /usr/lib/miralib. + +(a) predefined typenames + bool char num sys_message + +(b) predefined constructors + False True :: bool + Appendfile Closefile Exit Stderr Stdout System Tofile :: sys_message + +(c) predefined variables + abs and arctan cjustify code concat const converse cos decode digit + drop dropwhile e entier error exp filemode filter foldl foldl1 foldr + foldr1 force fst getenv hd hugenum id index init integer iterate + last lay layn letter limit lines ljustify log log10 map map2 max + max2 member merge min min2 mkset neg numval or pi postfix product + read readb rep repeat reverse rjustify scan seq showfloat showhex + shownum showoct showscaled sin snd sort spaces sqrt subtract sum + system take takewhile tinynum tl transpose undef until zip zip2 zip3 + zip4 zip5 zip6 (91) + +See manual entry `Standard environment' for a listing of its contents. + +[*You can suppress automatic inclusion of by calling mira with + flag "-stdenv". See manual section 31/7 "Options, setup files etc"] + diff --git a/miralib/manual/100 b/miralib/manual/100 new file mode 100644 index 0000000..83fbe5b --- /dev/null +++ b/miralib/manual/100 @@ -0,0 +1,578 @@ +FROM SIGPLAN NOTICES, 21(12):158-166, December 1986. (C) D.A.Turner + + + _A_n_ _O_v_e_r_v_i_e_w_ _o_f_ _M_i_r_a_n_d_a + + David Turner + Computing Laboratory + University of Kent + Canterbury CT2 7NF + ENGLAND + + +Miranda is an advanced functional programming system which runs under +the UNIX operating system (*). The aim of the Miranda system is to +provide a modern functional language, embedded in a convenient +programming environment, suitable both for teaching and as a general +purpose programming tool. The purpose of this short article is to give +a brief overview of the main features of Miranda. The topics we shall +discuss, in order, are: + + Basic ideas + The Miranda programming environment + Guarded equations and block structure + Pattern matching + Currying and higher order functions + List comprehensions + Lazy evaluation and infinite lists + Polymorphic strong typing + User defined types + Type synonyms + Abstract data types + Separate compilation and linking + Current implementation status + +(*) _N_o_t_e: UNIX is a trademark of AT&T Bell Laboratories, Miranda is a + trademark of Research Software Ltd. + +_B_a_s_i_c_ _i_d_e_a_s + The Miranda programming language is purely functional - there are no +side effects or imperative features of any kind. A program (actually we +don't call it a program, we call it a "script") is a collection of +equations defining various functions and data structures which we are +interested in computing. The order in which the equations are given is +not in general significant. There is for example no obligation for the +definition of an entity to precede its first use. Here is a very simple +example of a Miranda script: + z = sq x / sq y + sq n = n * n + x = a + b + y = a - b + a = 10 + b = 5 +Notice the absence of syntactic baggage - Miranda is, by design, rather +terse. There are no mandatory type declarations, although (see later) +the language is strongly typed. There are no semicolons at the end of +definitions - the parsing algorithm makes intelligent use of layout. +Note that the notation for function application is simply juxtaposition, +as in "sq x". In the definition of the sq function, "n" is a formal +parameter - its scope is limited to the equation in which it occurs +(whereas the other names introduced above have the whole script for +their scope). + +The most commonly used data structure is the list, which in Miranda is +written with square brackets and commas, eg: + week_days = ["Mon","Tue","Wed","Thur","Fri"] + days = week_days ++ ["Sat","Sun"] +Lists may be appended by the "++" operator. Other useful operations on +lists include infix ":" which prefixes an element to the front of a +list, "#" which takes the length of a list, and infix "!" which does +subscripting. So for example 0:[1,2,3] has the value [0,1,2,3], #days +is 7, and days!0 is "Mon". + +There is also an operator "--" which does list subtraction. For example +[1,2,3,4,5] -- [2,4] is [1,3,5]. + +There is a shorthand notation using ".." for lists whose elements form +an arithmetic series. Here for example are definitions of the factorial +function, and of a number "result" which is the sum of the odd numbers +between 1 and 100 (sum and product are library functions): + fac n = product [1..n] + result = sum [1,3..100] + +The elements of a list must all be of the same type. A sequence of +elements of mixed type is called a tuple, and is written using +parentheses instead of square brackets. Example + employee = ("Jones",True,False,39) +Tuples are analogous to records in Pascal (whereas lists are analogous +to arrays). Tuples cannot be subscripted - their elements are extracted +by pattern matching (see later). + +_T_h_e_ _p_r_o_g_r_a_m_m_i_n_g_ _e_n_v_i_r_o_n_m_e_n_t + The Miranda system is interactive and runs under UNIX as a self +contained subsystem. The basic action is to evaluate expressions, +supplied by the user at the terminal, in the environment established by +the current script. For example evaluating "z" in the context of the +first script given above would produce the result "9.0". + +The Miranda compiler works in conjunction with an editor (by default +this is "vi" but it can be set to any editor of the user's choice). +Scripts are automatically recompiled after edits, and any syntax or type +errors signalled immediately. The polymorphic type system permits a +high proportion of logical errors to be detected at compile time. + +There is quite a large library of standard functions. There is also an +online reference manual. The interface to UNIX permits Miranda programs +to take data from, and send data to, UNIX files and it is also possible +to invoke Miranda programs directly from the UNIX shell and to combine +them, via UNIX pipes, with processes written in other languages. + +_G_u_a_r_d_e_d_ _e_q_u_a_t_i_o_n_s_ _a_n_d_ _b_l_o_c_k_ _s_t_r_u_c_t_u_r_e + An equation can have several alternative right hand sides distinguished +by "guards" - the guard is written on the right following a comma. For +example the greatest common divisor function can be written: + gcd a b = gcd (a-b) b, _i_f a>b + = gcd a (b-a), _i_f a0 + _w_h_e_r_e + delta = b*b - 4*a*c + radix = sqrt delta + +Where clauses may occur nested, to arbitrary depth, allowing Miranda +programs to be organised with a nested block structure. Indentation of +inner blocks is compulsory, as layout information is used by the parser. + +(*) _N_o_t_e: In early versions of Miranda the keyword _i_f was not required. + +_P_a_t_t_e_r_n_ _m_a_t_c_h_i_n_g + It is permitted to define a function by giving several alternative +equations, distinguished by the use of different patterns in the formal +parameters. This provides another method of doing case analysis which +is often more elegant than the use of guards. We here give some simple +examples of pattern matching on natural numbers, lists and tuples. +Here is (another) definition of the factorial function, and a definition +of Ackermann's function: + fac 0 = 1 + fac (n+1) = (n+1) * fac n + + ack 0 n = n+1 + ack (m+1) 0 = ack m 1 + ack (m+1) (n+1) = ack m (ack (m+1) n) + +Here is a (naive) definition of a function for computing the n'th +Fibonacci number: + fib 0 = 0 + fib 1 = 1 + fib (n+2) = fib (n+1) + fib n + +Here are some simple examples of functions defined by pattern matching +on lists: + sum [] = 0 + sum (a:x) = a + sum x + + product [] = 1 + product (a:x) = a * product x + + reverse [] = [] + reverse (a:x) = reverse x ++ [a] + +Accessing the elements of a tuple is also done by pattern matching. For +example the selection functions on 2-tuples can be defined thus + fst (a,b) = a + snd (a,b) = b + +As final examples we give the definitions of two Miranda library +functions, take and drop, which return the first n members of a list, +and the rest of the list without the first n members, respectively + take 0 x = [] + take (n+1) [] = [] + take (n+1) (a:x) = a : take n x + + drop 0 x = x + drop (n+1) [] = [] + drop (n+1) (a:x) = drop n x + +Notice that the two functions are defined in such a way that that the +following identity always holds - "take n x ++ drop n x = x" - including +in the pathological case that the length of x is less than n. + +_C_u_r_r_y_i_n_g_ _a_n_d_ _h_i_g_h_e_r_ _o_r_d_e_r_ _f_u_n_c_t_i_o_n_s + Miranda is a fully higher order language - functions are first class +citizens and can be both passed as parameters and returned as results. +Function application is left associative, so when we write "f x y" it is +parsed as "(f x) y", meaning that the result of applying f to x is a +function, which is then applied to y. The reader may test out his +understanding of higher order functions by working out what is the value +of "answer" in the following script: + answer = twice twice twice suc 0 + twice f x = f (f x) + suc x = x + 1 + +Note that in Miranda every function of two or more arguments is actually +a higher order function. This is very useful as it permits partial +application. For example "member" is a library function such that +"member x a" tests if the list x contains the element a (returning True +or False as appropriate). By partially applying member we can derive +many useful predicates, such as + vowel = member ['a','e','i','o','u'] + digit = member ['0','1','2','3','4','5','6','7','8','9'] + month = member ["Jan","Feb","Mar","Apr","Jun","Jul","Aug","Sep", + "Oct","Nov","Dec"] + As another example of higher order programming consider the function +foldr, defined + foldr op k [] = k + foldr op k (a:x) = op a (foldr op k x) + +All the standard list processing functions can be obtained by partially +applying foldr. Examples + sum = foldr (+) 0 + product = foldr (*) 1 + reverse = foldr postfix [] + _w_h_e_r_e postfix a x = x ++ [a] + +_L_i_s_t_ _c_o_m_p_r_e_h_e_n_s_i_o_n_s + List comprehensions give a concise syntax for a rather general class of +iterations over lists. The syntax is adapted from an analogous notation +used in set theory (called "set comprehension"). A simple example of a +list comprehension is: + [ n*n | n <- [1..100] ] +This is a list containing (in order) the squares of all the numbers from +1 to 100. The above expression can be read as "list of all n*n such +that n is drawn from the list 1 to 100". Note that "n" is a local +variable of the above expression. The variable-binding construct to the +right of the bar is called a "generator" - the "<-" sign denotes that +the variable introduced on its left ranges over all the elements of the +list on its right. The general form of a list comprehension in Miranda +is: + [ body | qualifiers ] +Each qualifier is either a generator, of the form var<-exp, or else a +filter, which is a boolean expression used to restrict the ranges of the +variables introduced by the generators. When two or more qualifiers are +present they are separated by semicolons. An example of a list +comprehension with two generators is given by the following definition +of a function for returning a list of all the permutations of a given +list, + perms [] = [[]] + perms x = [ a:y | a <- x; y <- perms (x--[a]) ] + +The use of a filter is shown by the following definition of a function +which takes a number and returns a list of all its factors, + factors n = [ i | i <- [1..n _d_i_v 2]; n _m_o_d i = 0 ] + +List comprehensions often allow remarkable conciseness of expression. +We give two examples. Here is a Miranda statement of Hoare's +"Quicksort" algorithm, as a method of sorting a list, + sort [] = [] + sort (a:x) = sort [ b | b <- x; b<=a ] + ++ [a] ++ + sort [ b | b <- x; b>a ] + +Next is a Miranda solution to the eight queens problem. We have to +place eight queens on chess board so that no queen gives check to any +other. Since any solution must have exactly one queen in each column, a +suitable representation for a board is a list of integers giving the row +number of the queen in each successive column. In the following script +the function "queens n" returns all safe ways to place queens on the +first n columns. A list of all solutions to the eight queens problem is +therefore obtained by printing the value of (queens 8) + queens 0 = [[]] + queens (n+1) = [ q:b | b <- queens n; q <- [0..7]; safe q b ] + safe q b = and [ ~checks q b i | i <- [0..#b-1] ] + checks q b i = q=b!i \/ abs(q - b!i)=i+1 + +_L_a_z_y_ _e_v_a_l_u_a_t_i_o_n_ _a_n_d_ _i_n_f_i_n_i_t_e_ _l_i_s_t_s + Miranda's evaluation mechanism is "lazy", in the sense that no +subexpression is evaluated until its value is known to be required. One +consequence of this is that is possible to define functions which are +non-strict (meaning that they are capable of returning an answer even if +one of their arguments is undefined). For example we can define a +conditional function as follows, + cond True x y = x + cond False x y = y +and then use it in such situations as "cond (x=0) 0 (1/x)". + +The other main consequence of lazy evaluation is that it makes it +possible to write down definitions of infinite data structures. Here +are some examples of Miranda definitions of infinite lists (note that +there is a modified form of the ".." notation for endless arithmetic +progressions) + ones = 1 : ones + repeat a = x + _w_h_e_r_e x = a : x + nats = [0..] + odds = [1,3..] + squares = [ n*n | n <- [0..] ] + perfects = [ n | n <- [1..]; sum(factors n) = n ] + primes = sieve [ 2.. ] + _w_h_e_r_e + sieve (p:x) = p : sieve [ n | n <- x; n _m_o_d p > 0 ] + +One interesting application of infinite lists is to act as lookup tables +for caching the values of a function. For example our earlier naive +definition of "fib" can be improved from exponential to linear +complexity by changing the recursion to use a lookup table, thus + fib 0 = 1 + fib 1 = 1 + fib (n+2) = flist!(n+1) + flist!n + _w_h_e_r_e + flist = map fib [ 0.. ] + +Another important use of infinite lists is that they enable us to write +functional programs representing networks of communicating processes. +Consider for example the Hamming numbers problem - we have to print in +ascending order all numbers of the form 2^a*3^b*5^c, for a,b,c>=0. +There is a nice solution to this problem in terms of communicating +processes, which can be expressed in Miranda as follows + hamming = 1 : merge (f 2) (merge (f 3) (f 5)) + _w_h_e_r_e + f a = [ n*a | n <- hamming ] + merge (a:x) (b:y) = a : merge x (b:y), _i_f ab + = a : merge x y, _o_t_h_e_r_w_i_s_e + +_P_o_l_y_m_o_r_p_h_i_c_ _s_t_r_o_n_g_ _t_y_p_i_n_g + Miranda is strongly typed. That is, every expression and every +subexpression has a type, which can be deduced at compile time, and any +inconsistency in the type structure of a script results in a compile +time error message. We here briefly summarise Miranda's notation for +its types. + +There are three primitive types, called num, bool, and char. The type +num comprises integer and floating point numbers (the distinction +between integers and floating point numbers is handled at run time - +this is not regarded as being a type distinction). There are two values +of type bool, called True and False. The type char comprises the +Latin-1 character set - character constants are written in single +quotes, using C escape conventions, e.g. 'a', '$', '\n' etc. + +If T is type, then [T] is the type of lists whose elements are of type +T. For example [[1,2],[2,3],[4,5]] is of type [[num]], that is list of +lists of numbers. String constants are of type [char], in fact a string +such as "hello" is simply a shorthand way of writing +['h','e','l','l','o']. + +If T1 to Tn are types, then (T1, ... ,Tn) is the type of tuples with +objects of these types as components. For example (True,"hello",36) is +of type (bool,[char],num). + +If T1 and T2 are types, then T1->T2 is the type of a function with +arguments in T1 and results in T2. For example the function sum is of +type [num]->num. The function quadsolve, given earlier, is of type +num->num->num->[num]. Note that "->" is right associative. + +Miranda scripts can include type declarations. These are written using +"::" to mean is of type. Example + sq :: num -> num + sq n = n * n +The type declaration is not necessary, however. The compiler is always +able to deduce the type of an identifier from its defining equation. +Miranda scripts often contain type declarations as these are useful for +documentation (and they provide an extra check, since the typechecker +will complain if the declared type is inconsistent with the inferred +one). + +Types can be polymorphic, in the sense of [Milner 1978]. This is +indicated by using the symbols * ** *** etc. as an alphabet of generic +type variables. For example, the identity function, defined in the +Miranda library as + id x = x +has the following type + id :: * -> * +this means that the identity function has many types. Namely all those +which can be obtained by substituting an arbitrary type for the generic +type variable, eg "num->num", "bool->bool", "(*->**) -> (*->**)" and so +on. + +We illustrate the Miranda type system by giving types for some of the +functions so far defined in this article + fac :: num -> num + ack :: num -> num -> num + sum :: [num] -> num + month :: [char] -> bool + reverse :: [*] -> [*] + fst :: (*,**) -> * + snd :: (*,**) -> ** + foldr :: (*->**->**) -> ** -> [*] -> ** + perms :: [*] -> [[*]] + +_U_s_e_r_ _d_e_f_i_n_e_d_ _t_y_p_e_s + The user may introduce new types. This is done by an equation in +"::=". For example a type of labelled binary trees (with numeric +labels) would be introduced as follows, + tree ::= Nilt | Node num tree tree + +This introduces three new identifiers - "tree" which is the name of the +type, and "Nilt" and "Node" which are the constructors for trees - note +that constructors must begin with an upper case letter. Nilt is an +atomic constructor, while Node takes three arguments, of the types +shown. Here is an example of a tree built using these constructors + t1 = Node 7 (Node 3 Nilt Nilt) (Node 4 Nilt Nilt) + +To analyse an object of user defined type, we use pattern matching. For +example here is a definition of a function for taking the mirror image +of a tree + mirror Nilt = Nilt + mirror (Node a x y) = Node a (mirror y) (mirror x) + +User defined types can be polymorphic - this is shown by introducing one +or more generic type variables as parameters of the "::=" equation. For +example we can generalise the definition of tree to allow arbitrary +labels, thus + tree * ::= Nilt | Node * (tree *) (tree *) +this introduces a family of tree types, including tree num, tree bool, +tree (char->char), and so on. + +The types introduced by "::=" definitions are called "algebraic types". +Algebraic types are a very general idea. They include scalar +enumeration types, eg + color ::= Red | Orange | Yellow | Green | Blue | Indigo | Violet + +and also give us a way to do union types, for example + bool_or_num ::= Left bool | Right num + +It is interesting to note that all the basic data types of Miranda could +be defined from first principles, using "::=" equations. For example +here are type definitions for bool, (natural) numbers and lists, + bool ::= True | False + nat ::= Zero | Suc nat + list * ::= Nil | Cons * (list *) +Having types such as "num" built in is done for reasons of efficiency - +it isn't logically necessary. + +_N_o_t_e: In versions of Miranda before release two (1989) it was possible +to associate "laws" with the constructors of an algebraic type, which +are applied whenever an object of the type is built. For details see +[Turner 1985, Thompson 1986]. This feature was little used and since +has been removed from the language. + +_T_y_p_e_ _s_y_n_o_n_y_m_s + The Miranda programmer can introduce a new name for an already existing +type. We use "==" for these definitions, to distinguish them from +ordinary value definitions. Examples + string == [char] + matrix == [[num]] + +Type synonyms are entirely transparent to the typechecker - it is best +to think of them as macros. It is also possible to introduce synonyms +for families of types. This is done by using generic type symbols as +formal parameters, as in + array * == [[*]] +so now eg `array num' is the same type as `matrix'. + +_A_b_s_t_r_a_c_t_ _d_a_t_a_ _t_y_p_e_s + In addition to concrete types, introduced by "::=" or "==" equations, +Miranda permits the definition of abstract types, whose implementation +is "hidden" from the rest of the program. To show how this works we +give the standard example of defining stack as an abstract data type +(here based on lists): + + _a_b_s_t_y_p_e stack * + _w_i_t_h empty :: stack * + isempty :: stack * -> bool + push :: * -> stack * -> stack * + pop :: stack * -> stack * + top :: stack * -> * + + stack * == [*] + empty = [] + isempty x = (x=[]) + push a x = (a:x) + pop (a:x) = x + top (a:x) = a + +We see that the definition of an abstract data type consists of two +parts. First a declaration of the form "abstype ... with ...", where +the names following the "with" are called the _s_i_g_n_a_t_u_r_e of the abstract +data type. These names are the interface between the abstract data type +and the rest of the program. Then a set of equations giving bindings +for the names introduced in the abstype declaration. These are called +the _i_m_p_l_e_m_e_n_t_a_t_i_o_n _e_q_u_a_t_i_o_n_s. + +The type abstraction is enforced by the typechecker. The mechanism +works as follows. When typechecking the implementation equations the +abstract type and its representation are treated as being the same type. +In the whole of the rest of the script the abstract type and its +representation are treated as two separate and completely unrelated +types. This is somewhat different from the usual mechanism for +implementing abstract data types, but has a number of advantages. It is +discussed at somewhat greater length in [Turner 85]. + +_S_e_p_a_r_a_t_e_ _c_o_m_p_i_l_a_t_i_o_n_ _a_n_d_ _l_i_n_k_i_n_g + The basic mechanisms for separate compilation and linking are extremely +simple. Any Miranda script can contain one or more directives of the +form + %include "pathname" +where "pathname" is the name of another Miranda script file (which might +itself contain include directives, and so on recursively - cycles in the +include structure are not permitted however). The visibility of names +to an including script is controlled by a directive in the included +script, of the form + %export names +It is permitted to export types as well as values. It is not permitted +to export a value to a place where its type is unknown, so if you export +an object of a locally defined type, the typename must be exported also. +Exporting the name of a "::=" type automatically exports all its +constructors. If a script does not contain an export directive, then +the default is that all the names (and typenames) it defines will be +exported (but not those which it acquired by %include statements). + +It is also permitted to write a _p_a_r_a_m_e_t_r_i_s_e_d script, in which certain +names and/or typenames are declared as "free". An example is that we +might wish to write a package for doing matrix algebra without knowing +what the type of the matrix elements are going to be. A header for such +a package could look like this: + %free { element :: type + zero, unit :: element + mult, add, subtract, divide :: element->element->element + } + + %export matmult determinant eigenvalues eigenvectors ... + || here would follow definitions of matmult, determinant, + || eigenvalues, etc. in terms of the free identifiers zero, + || unit, mult, add, subtract, divide + +In the using script, the corresponding %include statement must give a +set of bindings for the free variables of the included script. For +example here is an instantiation of the matrix package sketched above, +with real numbers as the chosen element type: + %include "matrix_pack" + { element == num; zero = 0; unit = 1 + mult = *; add = +; subtract = -; divide = / + } + +The three directives %include, %export and %free provide the Miranda +programmer with a flexible and type secure mechanism for structuring +larger pieces of software from libraries of smaller components. + +Separate compilation is administered without user intervention. Each +file containing a Miranda script is shadowed by an object code file +created by the system and object code files are automatically recreated +and relinked if they become out of date with respect to any relevant +source. (This behaviour is similar to that achieved by the +UNIX program "make", except that here the user is not required to write +a makefile - the necessary dependency information is inferred from the +%include directives in the Miranda source.) + +_C_u_r_r_e_n_t_ _i_m_p_l_e_m_e_n_t_a_t_i_o_n_ _s_t_a_t_u_s + An implementation of Miranda is available for a range of UNIX machines +including SUN-4/Sparc, DEC Alpha, MIPS, Apollo, Sequent Symmetry, +Sequent Balance, Silicon Graphics, IBM RS/6000, HP9000, PC/Linux. This +is an interpretive implementation which works by compiling Miranda +scripts to an intermediate code based on combinators. It is currently +running at 550 sites (as of August 1996). + +Licensing information can be obtained from the world wide web at + http://miranda.org.uk + + +REFERENCES + +Milner, R. "A Theory of Type Polymorphism in Programming" Journal of +Computer and System Sciences, vol 17, 1978. + +Thompson, S.J. "Laws in Miranda" Proceedings 4th ACM International +Conference on LISP and Functional Programming, Boston Mass, August 1986. + +Turner, D.A. "Miranda: A non-strict functional language with +polymorphic types" Proceedings IFIP International Conference on +Functional Programming Languages and Computer Architecture, Nancy +France, September 1985 (Springer Lecture Notes in Computer Science, vol +201). + +[Note - this overview of Miranda first appeared in SIGPLAN Notices, +December 1986. It has here been revised slightly to bring it up to +date.] + diff --git a/miralib/manual/11 b/miralib/manual/11 new file mode 100644 index 0000000..5830c60 --- /dev/null +++ b/miralib/manual/11 @@ -0,0 +1,86 @@ +_L_i_t_e_r_a_l_s + +Miranda has three types of literal constant - numerals, character +constants and string constants. + +Numerals are written in the following style + 12 5237563 24.6 4.5e13 0.63e-6 +A numeral containing decimal point and/or scale factor (`.' or `e') is +held internally as double precision (=64 bit) floating point, accuracy +approximately 17 significant figures. Integers are held in a different +internal representation, and have unbounded precision. + +The two kinds of number, integer and floating point, are both of type +`num', as far as the type-checker is concerned, and can be freely mixed +in calculations. There is automatic conversion from integer to float +when required, but not in the opposite direction. To convert from +floating point to integer, use `entier' (see standard environment). + +Negative numbers are denoted by applying the prefix `-' operator to a +numeral, thus: + -12 -4.5e13 +but note that the notation -12 is an expression, not a literal, so if +you wish to apply a function to it, you must write f (-12), not f -12, +which would be read as an attempt to subtract 12 from f. + +Integers can be written in hexadecimal (base 16) or octal (base 8) +notation starting with 0x or 0o, e.g. 4095 can also be written as 0xfff +or 0o7777. Floating point numbers can be expressed in hexadecimal +notation, optionally scaled by `p' followed by a power of 2. For +example 0x1.0p-2 means 0.25. + +Character constants are written using single quotes, thus + 'a' '0' '\n' +The type `char' includes all Unicode* characters, those outside ascii +and Latin-1 can be expressed by numeric escape codes, see below. + +Note that the functions code::char->num, decode::num->char convert +characters to and from their numeric codes. + +String constants are written using double quotes, thus + "hello dolly" "" "\n\n\n" + +Escape conventions in character and string constants are as in `C', +using the backslash character. + \' single quote + \" double quote + \\ the \ character itself + \a alarm + \b backspace + \f formfeed + \n newline + \r carriage return + \t tab + \v vertical tab +plus these numeric escapes which specify characters by code number. + \ddd up to 3 decimal digits [0-9] + \xffff up to 4 hex digits [0-9a-f] + \Xffffff up to 6 hex digits + +For escape codes to \999 you can use either decimal or hex, for example +the DELETE character can be written as \127 or \x7f. The \x and \X +forms cover the whole range of Unicode values. For example '\x3b3' is +the Greek letter lower case gamma and '\x20ac' is the euro sign. The \X +form is unlikely to be needed but is provided for completeness. + +Specifying a character by numeric code in a string or char constant has +the same effect as including it literally, so for example "£" and +"\163" are exactly the same string. + +Where a numeric escape code in a string is followed by a literal digit +(or hex digit for \x \X) the numeral can be padded with leading 0s to +force the correct parse. For example "\0078" is the alarm character \7 +followed by a literal '8', while "\78" is "N". + +Literal newlines are allowed inside string quotes if escaped by a +preceding backslash, in which case the newline is ignored (as in C). +Thus the string "hello dolly" can equally be written + "hello \ +dolly" + +A literal newline is not allowed inside character quotes. + +[* Unicode is an international standard providing numeric codes for the + symbols of practically all known human writing systems. Unicode + points 0-127 coincide with ascii and 128-255 with Latin-1.] + diff --git a/miralib/manual/12 b/miralib/manual/12 new file mode 100644 index 0000000..a464473 --- /dev/null +++ b/miralib/manual/12 @@ -0,0 +1,86 @@ +_T_o_k_e_n_i_s_a_t_i_o_n_ _a_n_d_ _l_a_y_o_u_t + +A Miranda script or expression is regarded as being composed of _t_o_k_e_n_s, +separated by _l_a_y_o_u_t. + +A token is one of the following - an identifier, a literal, a type +variable, or a delimiter. Identifiers and literals each have their own +manual section. A type variable is a sequence of one or more stars, +thus * ** *** etc. (see basic type structure). Delimiters are the +miscellaneous symbols, such as operators, parentheses, and keywords. A +formal definition of the syntax of tokens, including a list of all the +delimiters in given under `Miranda lexical syntax'. + +_R_U_L_E_S_ _A_B_O_U_T_ _L_A_Y_O_U_T + +Layout consists of white space characters (spaces, tabs, newlines and +formfeeds), and comments. A comment consists of a pair of adjacent +vertical bars, together with all the text to the right of the bars on +the same line. Thus + || this is a comment +Layout is not permitted inside tokens (except in char and string +constants, where it is significant) but may be inserted freely between +tokens to make scripts more readable. Layout is ignored by the compiler +except in two respects: + +1) At least one space (or other layout characters) must be present +between two tokens that would otherwise form an instance of a single +larger token. For example in + f 19 'b' +we have a function, f, applied to a number and a character, but if we +were to omit the two intervening spaces, the compiler would read this as +a single six-character identifier, because both digits and single-quotes +are legal characters in an identifier. (Where it is not required to +force the correct tokenisation, or because of the offside rule, see +below, the presence of layout between tokens is optional.) + +2) Certain syntactic objects (roughly, the right hand sides of +declarations -- for an exact account see those entities followed by a +`(;)' in the formal syntax) obey Landin's _o_f_f_s_i_d_e _r_u_l_e [Landin 1966]. +This requires that every token of the object lie either directly below +or to the right of its first token. A token which breaks this rule is +said to be `offside' with respect to that object and terminates its +parse. For example in + x = 2 < a + y = f q +the 'y' is offside with respect to the right hand side of the definition +of 'x' (because it is to the left of the initial '2'). In such a case +the trailing semicolon may be omitted from the right hand side of the +equation for x. + +It is because of the offside rule that Miranda scripts do not normally +contain explicit semicolons as terminators for definitions. The same +rule enables the compiler to determine the scopes of nested _w_h_e_r_e's by +looking at their indentation levels. For example in + f x = g y z + _w_h_e_r_e + y = (x+1)*(x-1) + z = p x (q y) + g r = groo (r+1) + +it is the offside rule which makes it clear that the definition of 'g' +is not local to the right hand side of the definition of 'f', but those +of 'y' and 'z' are. + +It is always possible to terminate a right hand side by an EXPLICIT +semicolon, instead of relying on the offside rule. For example the +above script could be written all in one line, as + f x = g y z _w_h_e_r_e y = (x+1)*(x-1); z = p x (q y);; g r = groo (r+1); + +Notice that we need TWO semicolons after the definition of z - the first +terminates the rhs of the definition of `z', and the second terminates +the larger rhs of which it is a part, namely that of the definition of +`f'. If we put only one semicolon at this point, the definition of `g' +would be local to that of `f'. + +This example should convince the reader that code using layout +information to show the block structure is much more readable, and this +is the normal practise. + +[_R_e_f_e_r_e_n_c_e P.J. Landin "The Next 700 Programming Languages", CACM vol 9 +pp157-165 (March 1966).] + +Note that an additional comment convention applies in scripts whose +first character is a `>'. See separate manual entry on `literate +scripts'. + diff --git a/miralib/manual/13/1 b/miralib/manual/13/1 new file mode 100644 index 0000000..c5e9198 --- /dev/null +++ b/miralib/manual/13/1 @@ -0,0 +1,22 @@ +_D_o_t_d_o_t_ _n_o_t_a_t_i_o_n + +The following abbreviations are provided for denoting lists, of type +[num], whose members form a finite or infinite arithmetic series. Let +`a', `b', `c' stand for arbitrary numeric expressions. + + [a..b] list of numbers from a to b inclusive, interval = 1 + [a..] infinite list starting at a and increasing by 1 + [a,b..c] arithmetic series, first member a, second member b, + last member not greater than c (if b-a non-negative) + or not less than c (if b-a negative). + [a,b..] infinite series starting at a, interval = (b-a) + +So the notation [1..10] has as value the list [1,2,3,4,5,6,7,8,9,10]. +Here are some more examples + + nats = [0..] + evens = [0,2..] + odds_less_than_100 = [1,3..99] + neg_odds = [-1,-3..] + tenths = [1.0,1.1 .. 2.0] + diff --git a/miralib/manual/13/2 b/miralib/manual/13/2 new file mode 100644 index 0000000..2e86d88 --- /dev/null +++ b/miralib/manual/13/2 @@ -0,0 +1,68 @@ +_L_i_s_t_ _c_o_m_p_r_e_h_e_n_s_i_o_n_s + + [exp | qualifiers] + +List of all `exp' such that `qualifiers'. If there are two or more +qualifiers they are separated by semicolons. Each qualifier is either a +generator, of which the allowed forms are + + pattern-list <- exp (first form) + + pattern <- exp, exp .. (second form) + +or else a filter, which is a boolean expression restricting the range of +the variables introduced by preceding generators. The variables +introduced on the left of each `<-' are local to the list comprehension. + +Some examples + + sqs = [ n*n | n<-[1..] ] + + factors n = [ r | r<-[1..n div 2]; n mod r = 0 ] + + knights_moves [i,j] = [ [i+a,j+b] | a,b<-[-2..2]; a^2+b^2=5 ] + +Notice that a list of variables on the lhs of a `<-' is shorthand for +multiple generators, e.g. `i,j<-thing' expands to `i<-thing; j<-thing'. + +The variables introduced by the generators come into scope from left to +right, so later generators can make use of variables introduced by +earlier ones. An example of this is shown by the following definition +of a function for generating all the permutations of a given list. + + perms [] = [[]] + perms x = [ a:p | a<-x; p<-perms(x--[a]) ] + +The second form of generator allows the construction of lists from +arbitrary recurrence relations, thus + x <- a, f x .. +causes x to assume in turn the values `a', `f a', `f(f a)', etc. + +An example of its use is in the following definition of the fibonacci +series + + fibs = [ a | (a,b) <- (1,1), (b,a+b) .. ] + +Another example is given by the following expression which lists the +powers of two + + [ n | n <- 1, 2*n .. ] + +The order of enumeration of a list comprehension with multiple +generators is like that of nested for-loops, with the rightmost +generator as the innermost loop. For example the value of the +comprehension [ f x y | x<-[1..4]; y<-[1..4] ] is + + [ f 1 1, f 1 2, f 1 3, f 1 4, f 2 1, f 2 2, f 2 3, f 2 4, + f 3 1, f 3 2, f 3 3, f 3 4, f 4 1, f 4 2, f 4 3, f 4 4 ] + +As a consequence of this order of enumeration of multiple generators, if +any generator other than the first (leftmost) is infinite, some +combinations of values will never be reached in the enumeration. To +overcome this a second, _d_i_a_g_o_n_a_l_i_s_i_n_g, form of list comprehension is +provided (see separate manual section). + +Note that list comprehensions do NOT remove duplicates from the result +list. To remove duplicates from a list, apply the standard function +`mkset'. + diff --git a/miralib/manual/13/3 b/miralib/manual/13/3 new file mode 100644 index 0000000..9cfbf11 --- /dev/null +++ b/miralib/manual/13/3 @@ -0,0 +1,33 @@ +_D_i_a_g_o_n_a_l_i_s_i_n_g_ _l_i_s_t_ _c_o_m_p_r_e_h_e_n_s_i_o_n_s + + [ exp // qualifiers ] + +Syntax and scope rules exactly as for standard list comprehensions, the +only difference being the use of `//' in place of the vertical bar. The +order of enumeration of the generators is such that it is guaranteed +that every possible combination of values will be reached eventually. +The diagonalisation algorithm used is "fair" in the sense that it gives +equal priority to all of the generators. + +For example the value of [f x y//x<-[1..4]; y<-[1..4]] is + + [ f 1 1, f 1 2, f 2 1, f 1 3, f 2 2, f 3 1, f 1 4, f 2 3, + f 3 2, f 4 1, f 2 4, f 3 3, f 4 2, f 3 4, f 4 3, f 4 4 ] + +The algorithm used used is "Cantorian diagonalisation" - imagine the +possible combinations of values from the two generators laid out in a +(perhaps infinite) rectangular array, and traverse each diagonal in turn +starting from the origin. The appropriate higher-dimensional analogue +of this algorithm is used for the case of a list comprehension with +three or more generators. + +As an example of an enumeration that could not be defined at all using a +standard list comprehension, because of the presence of several infinite +generators, here is a definition of the list of all pythagorean +triangles (right-angled triangles with integer sides) + + pyths = [(a,b,c)//a,b,c<-[1..];a^2+b^2=c^2] + +In the case that there is only one generator, the use of `//' instead of +`|' makes no difference to the meaning of the list comprehension. + diff --git a/miralib/manual/13/contents b/miralib/manual/13/contents new file mode 100644 index 0000000..543af82 --- /dev/null +++ b/miralib/manual/13/contents @@ -0,0 +1,6 @@ +_I_t_e_r_a_t_i_v_e_ _e_x_p_r_e_s_s_i_o_n_s + + 1. Dotdot expression + 2. List comprehensions + 3. Diagonalising list comprehensions + diff --git a/miralib/manual/14 b/miralib/manual/14 new file mode 100644 index 0000000..87d56f5 --- /dev/null +++ b/miralib/manual/14 @@ -0,0 +1,66 @@ +_S_c_r_i_p_t_s + +In Miranda the script is the persistent entity that is saved from +session to session (i.e. it plays the role of what is called a program +in conventional languages). Associated with a Miranda session at any +given time is a single current script, identified by a UNIX pathname +ending in `.m'. + +A script is a collection of declarations, establishing an environment in +which you wish to evaluate expressions. The order of the declarations +in a script is not significant - for example there is no requirement +that an identifier be defined before it is used. + +An identifier may not have more than one top-level binding in a given +script. + +Here are the kinds of declaration that can occur in a script: + +1) a definition (of a function, data structure etc. - see manual entry +`definitions' for more details). Example + fac n = product[1..n] + +2) a specification of the type of one or more identifiers, of the form + var-list :: +Example + fac :: num->num +See 'Basic type structure' for an account of possible types. Note that +these type specifications are normally optional, since the compiler is +able to deduce them from the definitions of the corresponding +identifiers. It is however possible to introduce an identifier by means +of a type specification only, without giving it a defining equation +(such identifiers are said to be `specified but not defined' and are +useful in program development). A special case of this is the +introduction of an otherwise undefined typename - see separate manual +entry on `placeholder types'. + +3) the definition of a user defined type - these are of three kinds, +synonyms, algebraic types, and abstract types (see separate manual entry +on each). + +4) a library directive (%export, %include or %free) these are used +specify the interfaces between separately compiled scripts - see +separate manual entry on the library mechanism. + +There is a manual entry giving the formal syntax of Miranda scripts. + +_N_o_t_e + A directory called `ex' (meaning `examples') containing a collection of +example scripts is supplied with the Miranda system, and will be found +under the `miralib' directory (usually kept at /usr/lib/miralib - the +Miranda session command `/miralib' will tell you where it is on your +system). + +A convention which the Miranda system consistently understands in +Miranda session commands, library directives etc. is that a pathname +enclosed in , instead of "string_quotes" is relative to +the miralib directory. In particular note that the Miranda session +command + /cd +will change your current directory to be "..../miralib/ex". You can +then say, e.g. + !ls +to see what's in there. In fact there is a README file, so a good thing +to say next would be + !vi README + diff --git a/miralib/manual/15 b/miralib/manual/15 new file mode 100644 index 0000000..e299ae3 --- /dev/null +++ b/miralib/manual/15 @@ -0,0 +1,92 @@ +_D_e_f_i_n_i_t_i_o_n_s + +The purpose of a definition is to give a value to one or more variables. +There are two kinds of definition, `scalar' and `conformal'. A scalar +definition gives a value to a single variable, and consists of one or +more consecutive equations of the form + fnform = rhs + +where a `fnform' consists of the name being defined followed by zero or +more formal parameters. Here are three examples of scalar definitions, +of `answer', `sqdiff' and `equal' respectively + answer = 42 + + sqdiff a b = a^2 - b^2 + + equal a a = True + equal a b = False + +When a scalar definition consists of more than one equation, the order +of the equations can be significant, as the last example shows. (Notice +that `equals' as defined here is a function of two arguments with the +same action as the built in `=' operator of boolean expressions.) + +A conformal definition gives values to several variables simultaneously +and is an equation of the form + pattern = rhs + +An example of this kind of definition is + (x,y,z) = ploggle + +For this to make sense, the value of `ploggle' must of course be a +3-tuple. More information about the _p_a_t_t_e_r_n _m_a_t_c_h_i_n_g aspect of +definitions is given in the manual section of that name. + +Both fnform and pattern equations share a common notion of `right hand +side' + +_R_i_g_h_t_ _h_a_n_d_ _s_i_d_e_s + +The simplest form of rhs is just an expression (as in all the equations +above). It is also possible to give several alternative expressions, +distinguished by guards. A guard consists of the word `if' followed by +a boolean expression. An example of a right hand side with several +alternatives is given by the following definition of the greatest common +divisor function, using Euclid's algorithm + gcd a b = gcd (a-b) b, _i_f a>b + = gcd a (b-a), _i_f a=q + _w_h_e_r_e + p = x^2 + 1 + q = 3*x^3 - 5 + +Notice that the whole _w_h_e_r_e clause must be indented, to show that it is +part of the rhs. Following a _w_h_e_r_e can be any number of definitions, +and the syntax of such local definitions is exactly the same as that for +top level definitions (including therefore, recursively, the possibility +that they may contain nested _w_h_e_r_e's). + +It is not permitted to have locally defined types, however. New +typenames can be introduced only at top level. + diff --git a/miralib/manual/16 b/miralib/manual/16 new file mode 100644 index 0000000..143a27d --- /dev/null +++ b/miralib/manual/16 @@ -0,0 +1,174 @@ +_P_a_t_t_e_r_n_ _M_a_t_c_h_i_n_g + +The notion of `pattern' plays an important role in Miranda. There are +three contexts in which patterns can be used - in function definitions, +in conformal definitions, and on the left of the `<-' in list +comprehensions. We first explain the general rules for pattern +formation, which are the same in all three contexts. + +Patterns are built from variables and constants, using constructors. +Here are some simple examples. + x + 3 + (x,y,3) +The first pattern is just the variable x, the second is the constant 3, +the last example is built from two variables and a constant, using the +(,,) constructor for 3-tuples. The components of a structured pattern +can themselves be arbitrary patterns, permitting nested structures of +any depth. + +A pattern can also contain repeated variables, e.g. `(x,1,x)'. A +pattern containing repeated variables matches a value only when the +parts of the value corresponding to occurrences of the same variable are +equal. + +The constructors which can be used in a pattern include those of tuple +formation `(..,..)', list formation `[..,..]', and the constructors of +any user defined Algebraic Type (see separate manual section). In +addition there are special facilities for matching on lists and natural +numbers, as follows. + +(Lists) The `:' operator can be used in patterns, so for example the +following three patterns are all equivalent (and will match any 2-list). + a:b:[] + a:[b] + [a,b] +Note that `:' is right associative (see manual section on Operators). + +(Natural numbers) It is permitted to write patterns of the form `p+k' +where p is a pattern and k is a literal integer constant. This +construction will succeed in matching a value n, if and only if n is an +integer >=k, and in this case p is bound to (n-k). Example, `y+1' +matches any positive integer, and `y' gets bound to the +integer-minus-one. + +Note that the automatic coercion from integer to floating point, which +takes place in expression evaluation, does not occur in pattern +matching. An integer pattern such as `3' or `n+1' will not match any +floating point number. It is not permitted to write patterns containing +floating point constants. + +_C_a_s_e_ _a_n_a_l_y_s_i_s + +The main use of pattern matching in Miranda is in the left hand side of +function definitions. In the simplest case a pattern is used simply to +provide the right hand side of the function definition with names for +subcomponents of a data structure. For example, functions for accessing +the elements of a 2-tuple may be defined, + fst_of_two (a,b) = a + snd_of_two (a,b) = b + +More generally a function can be defined by giving a series of +equations, in which the use of different patterns on the left expresses +case analysis on the argument(s). Some simple examples + factorial 0 = 1 + factorial(n+1) = (n+1)*factorial n + + reverse [] = [] + reverse (a:x) = reverse x ++ [a] + + last [a] = a + last (a:x) = last x, if x~=[] + last [] = error "last of empty list" + +Many more examples can be found in the definition of the standard +environment (see separate manual section). Note that pattern matching +can be combined with the use of guards (see last example above). +Patterns in a case analysis do not have to be mutually exclusive +(although as a matter of programming style that is good practice) - the +rule is that cases are tried in order from top to bottom, and the first +equation which `matches' is used. + +_C_o_n_f_o_r_m_a_l_ _d_e_f_i_n_i_t_i_o_n_s + +Apart from the simple case where the pattern is a single variable, the +construction + pattern = rhs + +is called a `conformal definition'. If the value of the right hand hand +side matches the structure of the given pattern, the variables on the +left are bound to the corresponding components of the value. Example + [a,b,3] = [1,2,3] + +defines a and b to have the values 1 and 2 respectively. If the match +fails anywhere, all the variables on the left are _u_n_d_e_f_i_n_e_d. For +example, within the scope of the definition + (x,x) = (1,2) + +the value of x is neither 1 nor 2, but _u_n_d_e_f_i_n_e_d (i.e. an error message +will result if you try to access the value of x in any way). + +As a constraint to prevent "nonsense" definitions, it is a rule that the +pattern on the left hand side of a conformal definition must contain at +least one variable. So e.g. `1 = 2' is not a syntactically valid +definition. + +_P_a_t_t_e_r_n_s_ _o_n_ _t_h_e_ _l_e_f_t_ _o_f_ _g_e_n_e_r_a_t_o_r_s + +In a list comprehension (see separate manual entry) the bound entity on +the left hand side of an `<-' symbol can be any pattern. We give two +simple examples - in both examples we assume x is a list of 2-tuples. + +To denote a similar list but with the elements of each tuple swapped +over we can write + [(b,a)|(a,b)<-x] + +To extract from x all second elements of a 2-tuple whose first member is +17, we can write + [ b |(17,b)<-x] + +_I_r_r_e_f_u_t_a_b_l_e_ _p_a_t_t_e_r_n_s (*) + (Technical note, for people interested in denotational semantics) + +DEFINITION:- an algebraic type having only one constructor and for which +that constructor is non-nullary (ie has at least one field) is called a +_p_r_o_d_u_c_t _t_y_p_e. The constructor of a product type is called a `product +constructor'. + +Each type of n-tuple (n~=0) is also defined to be a product type. In +fact it should be clear that any user defined product type is isomorphic +to a tuple type. Example, if we define + wibney ::= WIB num bool +then the type wibney is isomorphic to the tuple type (num,bool). + +A pattern composed only of product-constructors and identifiers, and +containing no repeated identifiers, is said to be "irrefutable". For +example `WIB p q', `(x,y,z)' and `(a,(b,c))' are irrefutable patterns. +We show what this means by an example. Suppose we define f, by + + f :: (num,num,bool) -> [char] + f (x,y,z) = "bingo" + +As a result of the constraints of strong typing, f can only be applied +to objects of type (num,num,bool) and given any actual parameter of that +type, the above equation for f MUST match. + +Interestingly, this works even if the actual parameter is an expression +which does not terminate, or contains an error. (For example try typing + f undef +and you will get "bingo", not an error message.) + +This is because of a decision about the denotational semantics of +algebraic types in Miranda - namely that product types (as defined +above) correspond to the domain construction DIRECT PRODUCT (as opposed +to lifted product). This means that the bottom element of a type such +as (num,num,bool) behaves indistinguishably from (bottom,bottom,bottom). + +Note that singleton types such as the empty tuple type `()', or say, + it ::= IT +are not product types under the above definition, and therefore patterns +containing sui-generis constants such as () or IT are not irrefutable. +This corresponds to a semantic decision that we do NOT wish to identify +objects such as () or IT with the bottom element of their type. + +For a more detailed discussion of the semantics of Miranda see the +formal language definition (in preparation). + +------------------------------------------------------------------------ +(*) A useful discussion of the semantics of pattern-matching, including +the issue of irrefutable patterns, can be found in (chapter 4 of) the +following + S. L. Peyton-Jones ``The Implementation of Functional Programming + Languages'', Prentice Hall International, March 1987. + ISBN 0-13-453333-X + diff --git a/miralib/manual/17 b/miralib/manual/17 new file mode 100644 index 0000000..defbe49 --- /dev/null +++ b/miralib/manual/17 @@ -0,0 +1,66 @@ +_C_o_m_p_i_l_e_r_ _d_i_r_e_c_t_i_v_e_s + +Certain keywords, beginning with `%', modify the action of the compiler +when present in a script. These are called `compiler directives'. The +directives currently available are as follows. + +%list %nolist + If the `/list' feature is enabled (switched on and off by /list, +/nolist at command level) the compiler echos the source to the user's +terminal during compilation of a Miranda script. The directives %list, +%nolist may be placed in a file to give more detailed control over this +behaviour. If the compiler is in an echoing state then encountering +`%nolist' causes it to cease echoing from that point onwards in the +source, until the next occurrence of '%list' or the end of the source +file in which the directive occurs, whichever is the sooner. These +directives may occur anywhere in a script and have no effect on the +semantics (i.e. they are just like comments, apart from having a +side-effect on the lex analyser). + +If the `/list' feature of the compiler is not enabled these directives +are ignored. Since the default state of the compiler is now `/nolist' +these directives are of marginal value and retained only for historical +reasons. + +%insert + A directive of the form + %insert "pathname" +may occur anywhere in a Miranda script, and is textually replaced by the +contents of the file "pathname" during lexical analysis. The pathname +must be given as a literal string, enclosed in double quotes. (Most +uses of this directive are now better handled by %include, see below). + +If the %insert directive is textually indented in the file in which it +occurs, the whole of the inserted text will be treated as being indented +by the same amount as the initial `%' of the directive. + +Insert directives may be invoked recursively, to a depth limit imposed +by the operating system, typically about 16, which should be enough for +any reasonable purpose. Note that the pathnames are resolved +statically, not dynamically, so that the meaning of an _%_i_n_s_e_r_t directive +is computed relative to the file in which it occurs, NOT relative to the +directory from which the compiler was invoked. + +The use of static rather than dynamic pathname resolution is a departure +from normal UNIX conventions (both the `C' compiler and the UNIX shell +resolve pathnames dynamically) but is much more convenient in practice. + +Note that if the subject of an %insert directive is a complete Miranda +script it is always better to use %include (see manual section on the +library mechanism), since this avoids needless recompilation of the +definitions of the subsidiary script. The use of %include also imposes +a hierarchical scope discipline, and is more likely to lead to well +structured code. + +A point to beware of when using %insert is that unlike %include, it does +NOT add a missing `.m' extension to its pathname argument automatically. +This is because the argument file may contain an arbitrary piece of text +(e.g. an expression or a signature) and need not be a complete Miranda +script, so it would be inappropriate to insist that it's pathname end in +`.m' in all cases. + +%include %export %free + These directives control the identifier bindings between separately +compiled scripts. See separate manual entry on `the library mechanism' +for details. + diff --git a/miralib/manual/18 b/miralib/manual/18 new file mode 100644 index 0000000..d5cd0a4 --- /dev/null +++ b/miralib/manual/18 @@ -0,0 +1,114 @@ +_B_a_s_i_c_ _t_y_p_e_ _s_t_r_u_c_t_u_r_e_ _a_n_d_ _n_o_t_a_t_i_o_n_ _f_o_r_ _t_y_p_e_s + +The Miranda programming language is _s_t_r_o_n_g_l_y _t_y_p_e_d - that is each +expression and each variable has a type that can be deduced by a static +analysis of the program text. + +_P_r_i_m_i_t_i_v_e_ _t_y_p_e_s + num bool char + +Values of type `num' include both integer and floating point numbers, +e.g. + 23 0 -17 1.26e11 +They are stored using different internal representations, but can be +freely mixed in calculations, and are both of type `num' for type +checking purposes. There is automatic conversion from integer to +floating point when required (but not in the opposite direction - use +`entier', see standard environment). Floating point numbers are held to +double precision, integers to unbounded precision. + +The values of type `bool' are the two truth values: + True False + +The values of type `char' are characters in the Latin-1 character set, +e.g. + 'a' '%' '\t' + +_L_i_s_t_ _t_y_p_e_s + [t] is the type of lists whose elements are of type `t' + +Thus [num] is the type of lists of numbers such as [1,2,3,4,5] + +[[num]] is the type of lists of lists of numbers, such as [[1,2],[3,4]] + +[char] are lists of characters - this is also the type of string +constants, so e.g. ['h','e','l','l','o'] and "hello" are interchangeable +objects of this type. + +_T_u_p_l_e_ _t_y_p_e_s + (t1,...,tn) is the type of a tuple with elements of type `t1' to `tn' + +Example - the value (1,True,"red") is of type (num,bool,[char]) + +The type of the empty tuple, `()', is also written `()'. + +Notice that tuples are distinguished from lists by being enclosed in +parentheses, instead of square brackets. + +There is no concept of a 1-tuple, in Miranda, so the use of parentheses +to enclose subexpressions, as in say a*(b+c), does not conflict with +their use for tuple formation. + +_F_u_n_c_t_i_o_n_ _t_y_p_e_s + t1->t2 is the type of a function with argument type `t1' and result +type `t2' + +The '->' is right associative, so e.g. `num->num->num' is the type of a +curried function of two numeric arguments. + +In addition to the built-in types described above, user defined types +may be introduced - these are of three kinds, synonym types, algebraic +types and abstract types - see separate manual entry for each. + +_I_m_p_l_i_c_i_t_ _t_y_p_i_n_g + In Miranda the types of identifiers do NOT normally need to be declared +explicitly - the compiler is able to infer the type of identifiers from +their defining equations. For example if you write + plural x = x ++ "s" + +the compiler will DEDUCE that `plural' is of type [char]->[char]. It is +however permitted to include explicit type declarations in the script if +desired, e.g. you could write (anywhere in the same script) + plural :: [char]->[char] + +and the compiler will check this for consistency with the defining +equation (the symbol `::' means `is of type'). More generally the type +declared may be an _i_n_s_t_a_n_c_e (see below) of the type implied by the +definition - in this case the effect of the declaration is to restrict +the type of the identifier to be less general than it would otherwise +have been. + +Note that only top-level identifiers may be the subject of type +declarations, and that the type of an identifier may be declared at most +once in a given script. + + +_P_o_l_y_m_o_r_p_h_i_s_m + The final feature of the type system is that it permits polymorphic +types. There is an alphabet of generic type variables, written + * ** *** etc. + +each of which stands for an arbitrary type. We give a simple example - +the identity function, which may be defined + id x = x + +is attributed the type `*->*'. This means that `id' has many types - +`num->num', `char->char', `[[bool]]->[[bool]]' and so on - each of these +is an instance of its most general type, `*->*'. + +Another simple example of polymorphism is the function `map' (see +standard environment) which applies a function to every element of a +list. For example `map integer [1,1.5,2]' is [True,False,True]. The +type of map is + map :: (*->**) -> [*] -> [**] + +The most polymorphic possible object is `undef', the identifier which +stands for the undefined, or error value (undef is defined in the +standard environment). Since every type has an undefined value, the +correct type specification for undef is + undef :: * + +Many of the functions in the standard environment have polymorphic types +- the text of the standard environment (see separate manual entry) is +therefore a useful source of examples. + diff --git a/miralib/manual/19 b/miralib/manual/19 new file mode 100644 index 0000000..b3cb620 --- /dev/null +++ b/miralib/manual/19 @@ -0,0 +1,18 @@ +_T_y_p_e_ _s_y_n_o_n_y_m_ _d_e_c_l_a_r_a_t_i_o_n_s + +These permit the user to introduce a new name for an already existing +type, e.g. + string == [char] +type synonyms are entirely transparent to the typechecker (it best to +think of them as being just macros). For obvious reasons, recursive type +synonyms are not permitted. + +It is also possible to introduce a synonym for a type forming operator, +by introducing generic type variable as parameters of the definition, +e.g. + invt * ** == (*->**)->(**->*) + +So within a script containing the above two `==' definitions, the type +`invt num string' will be shorthand for + (num->[char])->([char]->num) + diff --git a/miralib/manual/2 b/miralib/manual/2 new file mode 100644 index 0000000..3cba655 --- /dev/null +++ b/miralib/manual/2 @@ -0,0 +1,23 @@ +_A_b_o_u_t_ _t_h_e_ _n_a_m_e_ _`_M_i_r_a_n_d_a_' + +The word `Miranda' is not an acronym. It is a proper name (like `ADA'). + +"Miranda (f). From the Latin meaning `to be admired'. This name was +first used by Shakespeare for the heroine of `The Tempest', a young girl +blessed with many admirable qualities. Like other unusual Shakespearean +names it has been used quite frequently in the 20th century." + + - Collins Dictionary of First Names, + William Collins and Son Ltd, London, 1967 + +"O wonder! How many goodly creatures are there here! O brave new world." + + - `The Tempest' by William Shakespeare + (from a speech by Miranda, Act 5, Scene 1) + +_I_m_p_o_r_t_a_n_t_ _N_o_t_e_. When used as the name of a functional programming +system, `Miranda' is a trademark (tm) of Research Software Ltd. + +Note that only the first letter of Miranda is upper case - it should +never be written all in capitals. + diff --git a/miralib/manual/20 b/miralib/manual/20 new file mode 100644 index 0000000..2ca09d5 --- /dev/null +++ b/miralib/manual/20 @@ -0,0 +1,126 @@ +_A_l_g_e_b_r_a_i_c_ _t_y_p_e_ _d_e_f_i_n_i_t_i_o_n_s + +The simplest method of introducing a new data type into a Miranda script +is by means of an algebraic type definition. This enables the user to +introduce a new concrete data type with specified constructors. A +simple example would be + tree ::= Nilt | Node num tree tree + +The `::=' sign is used to introduce an algebraic data type. This +definition introduces three new identifiers + `tree' a typename + `Nilt' a nullary constructor (i.e. an atom), of type tree + `Node' a constructor, of type num->tree->tree->tree + +Now we can define trees using constructors Nilt & Node, for example + t = Node 3 Nilt Nilt + +It is not necessary to have names for selector functions because the +constructors can be used in pattern matching. For example a function +for counting the number of nodes in a tree could be written + size Nilt = 0 + size (Node a x y) = 1 + size x + size y + +Note that the names of constructors _m_u_s_t_ _b_e_g_i_n_ _w_i_t_h_ _a_n_ _u_p_p_e_r_ _c_a_s_e_ _l_e_t_t_e_r +(and conversely, any identifier beginning with an upper case letter is +assumed to be a constructor). + +An algebraic type can have any number (>=1) of constructors and each +constructor can have any number (>=0) fields, of specified types. The +number of fields taken by a constructor is called its `arity'. A +constructor of arity zero is said to be atomic. Algebraic types are a +very general idea and include a number of special cases that in other +languages require separate constructions. + +One interesting case that all of the constructors can be atomic, giving +us what is called in PASCAL a `scalar enumeration type'. Example + day ::= Mon|Tue|Wed|Thu|Fri|Sat|Sun + +The union of two types can also be represented as an algebraic data type +- for example here is a union of num and bool. + boolnum ::= Left bool | Right num + +Notice that this is a `labelled union type' (the other kind of union +type, in which the parts of the union are not distinguished by tagging +information, is not permitted in Miranda). + +An algebraic typename can take parameters, thus introducing a family of +types. This is done be using generic type variables as formal +parameters of the `::=' definition. To modify our definition of `tree' +to allow trees with different types of labels at the nodes (instead of +all `num' as above) we would write + tree * ::= Nilt | Node * (tree *) (tree *) + +Now we have many different tree types - `tree num', `tree bool', +`tree([char]->[char])', and so on. The constructors `Node' and `Nilt' +are both polymorphic, with types `tree *' and `*->tree *->tree *->tree +*' respectively. + +Notice that in Miranda objects of a recursive user defined type are not +restricted to being finite. For example we can define the following +infinite tree of type `tree num' + bigtree = Node 1 bigtree bigtree + +_C_o_n_t_r_o_l_l_i_n_g_ _t_h_e_ _s_t_r_i_c_t_n_e_s_s_ _o_f_ _c_o_n_s_t_r_u_c_t_o_r_s + +Definition - a function f is strict iff + f _| = _| +where _| is the value attributed to expressions which fail to terminate +or terminate with an error. To support non-strict functions the calling +mechanism must not evaluate the arguments before passing them to the +function - this is what is meant by "lazy evaluation". + +In Miranda constructors are, by default, non-strict in all their fields. +Example + + pair ::= PAIR num num + fst (PAIR a b) = a + snd (PAIR a b) = b + +First note that there is a predefined identifier "undef" which denotes +undefined - evaluating "undef" in a Miranda session gives an error +message. Consider the following Miranda expressions: + + fst (PAIR 1 undef) + snd (PAIR undef 1) + +Both evaluate to `1', that is `PAIR' is non-strict in both arguments. + +The primary reason for making constructors non-strict in Miranda is that +it is necessary to support equational reasoning on Miranda scripts. (In +the example given, elementary equational reasoning from the definition +of `fst' implies that `fst(PAIR 1 anything)' should always have the +value `1'.) It is also as a consequence of constructors being non-strict +that Miranda scripts are able to define infinite data structures. + +It is, however, possible to specify that a given constructor of an +algebraic data type is strict in one or more fields by putting `!' after +the field in the `::=' definition of the type. For example we can +change the above script to make PAIR strict in both fields, thus + + pair ::= PAIR num! num! + fst (PAIR a b) = a + snd (PAIR a b) = b + +Now `fst (PAIR 1 undef)' and `snd (PAIR undef 1)' both evaluate to +undefined. It is a consequence of the `!' annotations that `PAIR a b' +is undefined when either a or b is undefined. It is also possible to +make PAIR strict in just one of its fields by having only one `!' in the +type definition. + +In the case of a recursively defined algebraic type, if all the +constructors having recursive fields are made strict in those fields it +ceases to be possible to construct infinite objects of that type. It is +also possible to deny the possibility of certain infinite structures +while permitting others. For example if we modify the definition of the +tree type first given above as follows + tree ::= Nilt | Node num tree! tree + +then it is still possible to construct trees which are infinite in their +right branch but not "left-infinite" ones. + +The main reason for allowing `!' annotations on Miranda data type +definitions is that one of the intended uses of Miranda is as a SEMANTIC +METALANGUAGE, in which to express the denotational semantics of other +programming languages. + diff --git a/miralib/manual/21 b/miralib/manual/21 new file mode 100644 index 0000000..57f1a4e --- /dev/null +++ b/miralib/manual/21 @@ -0,0 +1,133 @@ +_A_b_s_t_r_a_c_t_ _t_y_p_e_ _d_e_f_i_n_i_t_i_o_n_s + +These enable a new data type to be defined by data type abstraction from +an existing type. We give the classic example, that of defining `stack' +as an abstract data type (here based on lists) + _a_b_s_t_y_p_e stack * + _w_i_t_h empty::stack * + push::*->stack *->stack * + isempty::stack *->bool + top::stack *->* + pop::stack *->stack * + + stack * == [*] + empty = [] + push a x = a:x + isempty x = x=[] + top (a:x) = a + pop (a:x) = x + +The information given after `_w_i_t_h' is called the _s_i_g_n_a_t_u_r_e of the +abstract type - the definitions of the identifiers in the signature are +called the `implementation equations' (these are the six equations given +above). Outside of the implementation equations the information that +stacks are implemented as lists is not available - [] and empty for +example are incomparable objects of two different and unrelated types ( +[*] and stack * respectively). Only inside the implementation equations +are the abstract objects treated as being equivalent to their +representations. + +The implementation equations do not have to appear immediately after the +corresponding _a_b_s_t_y_p_e declaration - they can occur anywhere in the +script. For readability, however, it is strongly recommended that the +implementation equations appear immediately after the _a_b_s_t_y_p_e +declaration. + +Note that in Miranda there is no runtime cost associated with +administering an abstract data type. The responsibility for enforcing +the distinction between stacks and lists, for example, is discharged +entirely at compile time (by the type checker). The runtime +representation of a stack does not require any extra bits to distinguish +it from a list. As a result the Miranda programmer can freely use +abstract data types to structure his programs without incurring any loss +of efficiency by doing so. + +Notice that the mechanism used to introduce abstract data types in +Miranda does not depend on the hiding of identifiers, and in this +respect differs from the traditional approach. A fuller discussion of +the Miranda _a_b_s_t_y_p_e mechanism can be found in [*Turner 85]. + +------------------------------------------------------------------------ +(*) D. A. Turner ``Miranda: A Non-Strict Functional Language with +Polymorphic Types'', Proceedings IFIP Conference on Functional +Programming Languages and Computer Architecture, Nancy, France, +September 1985 (Springer Lecture Notes in Computer Science, vol. 201, pp +1-16). +------------------------------------------------------------------------ + +_T_h_e_ _p_r_i_n_t_ _r_e_p_r_e_s_e_n_t_a_t_i_o_n_ _o_f_ _a_b_s_t_r_a_c_t_ _o_b_j_e_c_t_s + ("advanced feature" - omit on first reading) + +Values belonging to an abstract type are not in general printable. If +the value of a command-level expression is of such a type it will +normally print simply as + + + +This is because the special function _s_h_o_w (which is actually a family of +functions, see elsewhere) has no general method for converting such +objects to a printable form. It is possible to extend the definition of +_s_h_o_w to include the ability to print members of an abstract type, using +some appropriate format. The convention for doing this is to include in +the definition of the abstract type a function with the name `showfoo' +(where `foo' is the name of the abstract type involved). + +We illustrate how this is done taking `stack' as the example. Suppose +we decide we wish stacks to print - using a syntax such that the output +could be read back in (e.g. by readvals - see elsewhere) to generate the +same stack. + + empty is to print as "empty" + push 1 empty is to print as "(push 1 empty)" + and so on. + +Note that we decide to fully parenthesise the output for safety - since +we do not know the larger context in which our stack output may be +embedded. + +Because `stack' is a polymorphic abstraction, showstack will need to +take as a parameter the appropriate show function for the element type +(which is num in the above examples, but could have been any type). We +add to the signature of stack the following function. + + showstack::(*->[char])->stack *->[char] + +To obtain the output format illustrated above, an appropriate definition +of showstack would be, + + showstack f [] = "empty" + showstack f (a:x) = "(push " ++ f a ++ " " ++ showstack f x ++ ")" + +If this definition is included in the script, stacks become printable, +using the specified format. The effect is to extend the behaviour of +the special built-in function _s_h_o_w to handle stacks, and all data +structures built using stacks (such as list of tree of stacks, stack of +stacks and so on). + +The general rule is as follows. Let `foo' be an abstract type name. To +make foo's printable, we need to define a `showfoo' thus: + + if foo is a simple type (not polymorphic) + showfoo :: foo -> [char] + + if foo is polymorphic in one type variable (foo *) + showfoo :: (*->[char]) -> foo * -> [char] + + if foo is polymorphic in two type variables (foo * **) + showfoo :: (*->[char]) -> (**->[char]) -> foo * ** -> [char] + +and so on. Note that the show function must be declared in the +signature of the abstract type, and that the name of the function is +significant - if we change its name from `showfoo' to `gobbledegook', +its definition will cease to have any effect on the behaviour of _s_h_o_w. +It also needs to have the right type, and if it does not, again its +presence will have no effect on the behaviour of _s_h_o_w (in this case the +compiler prints a warning message). + +[Note on library directives: If you %export an abstract type, foo say, +to another file, it is not necessary to %export the showfoo function +explicitly to preserve the correct printing behaviour - if an abstract +type comes into existence with a show function in its signature the +compiler will `remember' how to print objects of the type even in scopes +where the show function has no name.] + diff --git a/miralib/manual/22 b/miralib/manual/22 new file mode 100644 index 0000000..b967d27 --- /dev/null +++ b/miralib/manual/22 @@ -0,0 +1,35 @@ +_E_m_p_t_y_ _t_y_p_e_s (also called _P_l_a_c_e_h_o_l_d_e_r_ _t_y_p_e_s) + +An empty type has no values belonging to it (apart from the undefined +value, undef, which is a member of every type). Empty types are +declared as follows: + + widget :: _t_y_p_e + +this declares `widget' to be a type but gives it no values. + +Empty types can be used during program development as placeholders for +types whose representation is not yet decided. For example given the +above declaration we can give type specifications involving widget, e.g. + + foo :: num->widget->widget + gronk :: [widget]->widget + +and write code using `foo' and `gronk' which can be checked for type +correctness. At a later stage the specification of widget as an empty +type can be replaced by a non-empty type definition, using ==, ::=, or +_a_b_s_t_y_p_e, allowing foo, gronk, to be defined. + +Typenames declared as empty can have any arity, eg + table * ** :: _t_y_p_e +This creates a family of empty types, such as `table num bool' and so +on. They are all devoid of values (apart from undef). The general form +of this kind of specification is + tform-list :: _t_y_p_e +where `tform' consists of a typename followed by zero or more generic +type variables (and it is permitted to declare several such types +simultaneously, separated by commas, whence `tform-list'). + +An empty type may be considered equivalent to an algebraic type with no +constructors. + diff --git a/miralib/manual/23 b/miralib/manual/23 new file mode 100644 index 0000000..6c627a9 --- /dev/null +++ b/miralib/manual/23 @@ -0,0 +1,55 @@ +_T_h_e_ _u_s_e_ _o_f_ _`_s_h_o_w_'_ _f_o_r_ _c_o_n_v_e_r_t_i_n_g_ _o_b_j_e_c_t_s_ _t_o_ _t_h_e_i_r_ _p_r_i_n_t_ _r_e_p_r_e_s_e_n_t_a_t_i_o_n_s + +The need often arises to convert an arbitrary Miranda value to its +printable representation as a string. For numbers the function +`shownum' (of type num->[char]) can be used for this purpose. To be +able to do this conversion for any type of object would seemingly +require an infinite number of functions, one for each type. As a +solution to this problem Miranda provides a special keyword, `_s_h_o_w'. + +For any object x + _s_h_o_w x +is a string containing the printable representation of x. For example, +if x is a number the above expression is equivalent to `shownum x'. In +the general case, however, x could be a structured object of arbitrary +complexity. Note that _s_h_o_w is a reserved word, not an identifier. + +In fact `_s_h_o_w' behaves under most circumstances as though it was the +name of a function, of type *->[char]. For example it can be passed as +a parameter, so that say, + map _s_h_o_w [a,b,c,d,e] +is a legal expression of type [[char]]. + +There are three important restrictions on the universality of _s_h_o_w. + +(i) You cannot `show' functions in any useful sense. (That would be a +violation of referential transparency.) The result of applying _s_h_o_w to +any kind of function is just the string "". + +(ii) You cannot `show' an abstract object unless an appropriate +show-function was included when the type was defined (see manual section +on Abstract types). The result of applying _s_h_o_w to such an object is by +default just the string "". + +(iii) When it occurs in a script the context in which _s_h_o_w is used must +be such as to determine its type _m_o_n_o_m_o_r_p_h_i_c_a_l_l_y. An example: + my_show x = "hello\n"++_s_h_o_w x++"goodbye\n" +In the absence of any other type information, the compiler will infer +that my_show has type *->[char], and that x is of type `*'. The use of +_s_h_o_w is therefore polymorphic, and will be rejected as illegal. + +If however we intend that my_show will be used only on objects of type +`tree', say, and we add to the script the declaration +`my_show::tree->[char]', then the above use of _s_h_o_w becomes monomorphic, +and will be accepted. + +The essence of restriction (iii) is that _s_h_o_w is not a true polymorphic +function of type *->[char], but rather a family of monomorphic functions +with the types T->[char] for each possible monotype T. The context must +be sufficient for the compiler to determine which member of the family +is required. + +(For technical reasons this restriction applies only in scripts. In +command-level expressions _s_h_o_w behaves as if it were a genuine +polymorphic function.) + diff --git a/miralib/manual/24 b/miralib/manual/24 new file mode 100644 index 0000000..b30a892 --- /dev/null +++ b/miralib/manual/24 @@ -0,0 +1,58 @@ +_S_y_n_t_a_x_ _o_f_ _M_i_r_a_n_d_a_ _s_c_r_i_p_t_s_ _a_n_d_ _e_x_p_r_e_s_s_i_o_n_s + +script:= decl* rhs:= simple_rhs(;) + cases +decl:= def + tdef simple_rhs:= exp whdefs? + spec + libdir cases:= alt(;) = cases + lastcase(;) +def:= fnform = rhs + pat = rhs alt:= exp , _i_f exp + +tdef:= tform == type(;) lastcase:= lastalt whdefs? + tform ::= constructs(;) + _a_b_s_t_y_p_e tform-list _w_i_t_h sig(;) lastalt:= exp , _i_f exp + exp , _o_t_h_e_r_w_i_s_e +spec:= var-list :: type(;) + tform-list :: _t_y_p_e(;) whdefs:= _w_h_e_r_e def def* + +sig:= spec spec* exp:= e1 + prefix1 +constructs:= construct | constructs infix + construct + e1:= simple simple* +construct:= constructor argtype* prefix e1 + type $constructor type e1 infix e1 + ( construct ) argtype* + simple:= var +type:= argtype constructor + typename argtype* literal + type -> type _r_e_a_d_v_a_l_s + type $typename type _s_h_o_w + ( infix1 e1 ) +argtype:= typename ( e1 infix ) + typevar ( exp-list? ) + ( type-list? ) [ exp-list? ] + [ type-list ] [ exp .. exp? ] + [ exp , exp .. exp? ] +tform:= typename typevar* [ exp | qualifs ] + typevar $typename typevar [ exp // qualifs ] + +fnform:= var formal* qualifs:= qualifier ; qualifs + pat $var pat qualifier + ( fnform ) formal* + qualifier:= exp +pat:= formal generator + -numeral + constructor formal* generator:= pat-list <- exp + pat : pat pat <- exp , exp .. + pat + nat + pat $constructor pat var:= identifier + ( pat ) formal* + constructor:= IDENTIFIER +formal:= var + constructor typename:= identifier + literal1 + ( pat-list? ) + [ pat-list? ] diff --git a/miralib/manual/25 b/miralib/manual/25 new file mode 100644 index 0000000..6e0cef9 --- /dev/null +++ b/miralib/manual/25 @@ -0,0 +1,80 @@ +_C_o_m_m_e_n_t_s_ _o_n_ _t_h_e_ _s_y_n_t_a_x_ _f_o_r_ _M_i_r_a_n_d_a_ _s_c_r_i_p_t_s + +The syntax equations given express the syntax of Miranda scripts insofar +as this can be done by a context free grammar. It therefore does not +attempt to express the scope rules, nor the requirement that a script be +well-typed, both of which are context sensitive restrictions on the +syntax given here. The formal definition of Miranda [in preparation] +will deal with these matters and also give a denotational semantics for +the language. + +Nevertheless, if the syntax is read in conjunction with the informal +description of the language (see other manual sections and referenced +papers) it should be found fairly informative, especially if the reader +has some previous exposure to this style of language. + +Key to abbreviations in syntax:- +> alt=alternative decl=declaration def=definition +> e1=operator_expression exp=expression fnform=function_form +> libdir=library_directive pat=pattern qualifs=qualifiers +> rhs=right_hand_side sig=signature spec=specification +> tdef=type_definition tform=typeform var=variable +> whdefs=where_defs + +_C_o_n_v_e_n_t_i_o_n_s + We use a variant of BNF, in which non-terminals are represented by +lower case words, `:=' is used as the production symbol, and alternative +productions are written on successive lines. (These departures from +convention are adopted because `::=' and `|' are concrete symbols of the +language.) + +For any non-terminal x, + x* means zero or more occurrences of x + x? means the presence of x is optional + x-list means one or more x's (separated by commas if >1) + x(;) means that x is followed by an optional semicolon and +is subject to the _o_f_f_s_i_d_e _r_u_l_e (see section on Layout), so that every +token of x must lie below or to the right of the first. Provided the +layout makes it clear where x terminates, the trailing semicolon may be +omitted. + +_N_o_t_e_s + +The syntax of the library directives (denoted by the non-terminal +`libdir') is given in a separate manual entry. + +Ambiguities in the syntax for `type' and `construct' are resolved by +noting that `->' is less binding than `$typename' or `$constructor' and +that all three are right associative. + +In connection with the productions for argtype, note that type such as +`[num,bool]' is an abbreviation for `[(num,bool)]' and represents the +type of a list of tuples - the Miranda system itself never uses this +abbreviation when printing a type, but accepts it in user scripts. (Use +of this abbreviation is not recommended - it will probably be removed +from the syntax at the next release.) + +Ambiguities in the syntax for `fnform' and `pat' are resolved by taking +into account the relative binding powers of the infix operators +involved. Specifically that `:' is right associative and less binding +than `+', which is left associative, and that $constructor, $var have a +higher binding power than either of these, and are right associative. + +The productions given for `cases' correctly describe the concrete syntax +of these entities, including the way the offside rule is applied to +them. This concrete syntax is in one sense misleading, however. Namely +in that if a `lastcase' with a trailing `wheredefs' is preceded by a +series of alternatives, the scope of the names introduced by the _w_h_e_r_e +IS THE WHOLE `cases' IN WHICH IT OCCURS, AND NOT JUST THE `lastcase'. + +Note that for compatibility with earlier versions of Miranda the use of +the keyword `if' is optional. + +The ambiguities in the syntax given for `e1' are resolved by taking into +account the relative binding powers of the operators (see manual section +on Operators). + +The syntax of identifier, IDENTIFIER, literal, literal1, numeral, nat, +infix, infix1, prefix, prefix1, and typevar are given under Lexical +Syntax (see next manual section). + diff --git a/miralib/manual/26 b/miralib/manual/26 new file mode 100644 index 0000000..af0fbcc --- /dev/null +++ b/miralib/manual/26 @@ -0,0 +1,72 @@ +_M_i_r_a_n_d_a_ _l_e_x_i_c_a_l_ _s_y_n_t_a_x + In this section square brackets are used to enclose a set of literal +characters, using lex-style conventions, so eg [a-z] means a lower case +letter. As usual * and ? are used to mean zero-or-more, and +zero-or-one, occurrences of the preceding entity. Parentheses are used +for grouping, and subtraction of one syntactic entity from another means +set difference. We also revert to using `|' for alternatives, as in +standard BNF. + +script:= (token | layout)* + +layout:= nl | tab | formfeed | space | comment + +comment:= vertical_bar vertical_bar (any - nl)* nl + +token:= identifier | IDENTIFIER | literal | typevar | delimiter + +identifier:= ([a-z] [a-zA-Z0-9_']* ) - delimiter + +IDENTIFIER:= [A-Z] [a-zA-Z0-9_']* + +literal:= numeral | charconst | stringconst + +literal1:= literal - float + +numeral:= nat | float + +nat:= [0-9] [0-9]* | 0x [0-9a-f] [0-9a-f]* | 0o [0-7] [0-7]* + +float:= [0-9]* [.] nat epart? | nat epart + +epart:= [e] [+|-]? nat + +charconst:= ['] (visible-[\]|escape) ['] + +stringconst:= ["] (visible-[\"]|escape)* ["] + +escape:= [\] ([ntfrb\'"]|nl|decimal_code) + +typevar:= [*][*]* + +delimiter:= - | prefix1 | infix1 | other + +infix1:= ++ | -- | : | \/ | & | > | >= | = | ~= | <= | < | + | * | + / | div | mod | ^ | . | ! | $identifier | $IDENTIFIER + +infix:= infix1 | - + +prefix1:= ~ | # + +prefix:= prefix1 | - + +other:= abstype | if | otherwise | readvals | show | type | where | + with | %export | %free | %include | %insert | %list | %nolist | + = | == | ::= | :: | => | vertical_bar | // | -> | ; | , | ( | + ) | [ | ] | { | } | <- | .. | $$ | $- | $:- | $+ | $* + +vertical_bar:= | + +_N_o_t_e_s + visible means any non-control character, including space (but not +including eg newline), nl means literal newline, and decimal_code is a +nat in the range 0..255 (maximum length 3 digits). + +Notice that the syntax of `numeral' does not include negative numbers. +Negative constants, such as -3 or -5.05e-17 are parsed by Miranda as +applications of the prefix operator `-' to a positive numeral. This has +no semantic significance. + +Omission - the definition of `layout' does not include the additional +comment rules for LITERATE SCRIPTS (see separate manual section). + diff --git a/miralib/manual/27/1 b/miralib/manual/27/1 new file mode 100644 index 0000000..0b785fc --- /dev/null +++ b/miralib/manual/27/1 @@ -0,0 +1,19 @@ +_S_y_n_t_a_x_ _o_f_ _l_i_b_r_a_r_y_ _d_i_r_e_c_t_i_v_e_s + +libdir:= %_i_n_c_l_u_d_e env(;) parts:= part part* + %_e_x_p_o_r_t parts(;) + %_f_r_e_e { sig } part:= identifier + fileid +env:= fileid binder? aliases? + + -identifier +binder:= { binding binding* } + fileid:= "pathname" +binding:= var = exp(;) + tform == type(;) + _N_o_t_e_s For the definition of `sig' +aliases:= alias alias* (=signature), `var', `exp', `tform' + and `type' see the main manual page +alias:= identifier/identifier on formal syntax of Miranda. For + IDENTIFIER/IDENTIFIER the definition of `identifier' and + -identifier `IDENTIFIER' see lexical syntax. + diff --git a/miralib/manual/27/2 b/miralib/manual/27/2 new file mode 100644 index 0000000..c53c3f0 --- /dev/null +++ b/miralib/manual/27/2 @@ -0,0 +1,44 @@ +_T_h_e_ _%_i_n_c_l_u_d_e_ _d_i_r_e_c_t_i_v_e_ _(_b_a_s_i_c_ _i_n_f_o_r_m_a_t_i_o_n_) + +Suppose the file "mylib.m" contains some Miranda declarations (which +could be any kind of legal Miranda declaration, eg function definitions, +type definitions etc). To make these in scope in another script, the +latter will contain the directive + %_i_n_c_l_u_d_e "mylib" + +This can come anywhere in the script (there is for example no +requirement that %_i_n_c_l_u_d_e directives come at the front) but must be at +top level - you may not place a %_i_n_c_l_u_d_e directive inside a _w_h_e_r_e +clause. The subject of a %_i_n_c_l_u_d_e directive may itself contain %_i_n_c_l_u_d_e +directives, and so on (to any reasonable depth). + +By default, the names `exported' from an included script are all those +defined in it at top level, but not those of subsidiary %_i_n_c_l_u_d_e's. +This can be modified by placing a `%_e_x_p_o_r_t' directive in the included +script. For a discussion of this and other ways of modifying the effect +of %_i_n_c_l_u_d_e see the manual section giving a detailed account of the +library directives. + +If the filename in a _%_i_n_c_l_u_d_e directive is enclosed in angle brackets +instead of string quotes, this is understood to be a pathname relative +to the miralib directory. So for example putting in your script + %_i_n_c_l_u_d_e +brings into scope the definitions exported from the matrix package in +the Miranda examples directory `ex'. (*See note below.) + +Finally, note that that the relationship between includor and includee +is unsymmetrical. If file A %_i_n_c_l_u_d_e's file B, then the declarations of +B are visible to A, but not vice versa. + +There is a simpler (purely textual) directive + %_i_n_s_e_r_t "file" +which causes the contents of "file" to be substituted for the %_i_n_s_e_r_t +directive during lexical analysis. This can occur anywhere in a Miranda +script. See manual section on compiler directives. + +------------------------------------------------------------------------ +(*) Note to system administrators: an empty directory `local' is +provided under the miralib directory, in which you can place additional +libraries which you wish to make available to all Miranda users at your +site. + diff --git a/miralib/manual/27/3 b/miralib/manual/27/3 new file mode 100644 index 0000000..5891ed2 --- /dev/null +++ b/miralib/manual/27/3 @@ -0,0 +1,286 @@ +_E_x_p_l_a_n_a_t_i_o_n_ _o_f_ _l_i_b_r_a_r_y_ _d_i_r_e_c_t_i_v_e_s + +The three directives %_i_n_c_l_u_d_e %_e_x_p_o_r_t %_f_r_e_e constitute the Miranda +library mechanism, which controls the sharing of identifiers between +separately compiled scripts. The %_f_r_e_e directive is covered in a +separate manual entry and will not be discussed further here. +------------------------------------------------------------------------ + +%_i_n_c_l_u_d_e "file" + +The presence of this directive, anywhere in a Miranda script, causes all +the identifiers exported from the Miranda script "file" to be in scope +in the containing script. Note that "file" should be the name of a +Miranda source file (by convention these all have names ending in `.m'). + +The following conventions apply to all filenames in library directives: + 1) A fileid can be an arbitrary UNIX pathname + 2) If the fileid given does not end in `.m' this is added. + 3) If the fileid is surrounded by angle brackets instead of string +quotes it is assumed to be a pathname relative to the `miralib' +directory, otherwise it is taken to be relative to the directory of the +script in which the directive occurs. (Examples, "pig" means "pig.m", + means "/usr/lib/miralib/stdenv.m") + +In addition (if you are using Berkeley UNIX or a derivative) the `~' +convention of the cshell may be used to abbreviate home directories. +That is `~' abbreviates your own home directory, and ~jack abbreviates +jack's home directory, at the front of any pathname. + +The file mentioned in a %_i_n_c_l_u_d_e directive must contain a CORRECT, +CLOSED Miranda script. (That is it must have no syntax or type errors, +and no undefined names.) An attempt to %_i_n_c_l_u_d_e a file which violates +these conditions will be rejected by the compiler as a syntax error in +the script containing the %_i_n_c_l_u_d_e statement. + +It is also illegal to %_i_n_c_l_u_d_e a script which causes nameclashes, either +against top-level identifiers of the including script or those of other +%_i_n_c_l_u_d_e directives in the script. + +The effect of an %_i_n_c_l_u_d_e directive can be modified by following it with +one or more aliases (which are used to remove nameclashes between +identifiers exported from the included script and those of the current +script or of other %_i_n_c_l_u_d_e files). There are two forms of alias, +`new/old' which renames and `-old' which suppresses an identifier +altogether. + +For example suppose we wish to include the file "mike" but it contains +two identifiers, f and g say, which clash with top-level bindings of +these identifiers in the current script. We wish to use the "mike" +definition of `f', but his `g' is of no interest. The following +directive could be used. + +%_i_n_c_l_u_d_e "mike" -g mike_f/f + +Any other identifiers exported from "mike", not specifically mentioned +in the aliases, will be accepted unchanged. + +It is permitted to alias typenames, and constructors (say `NEW/OLD') but +typenames and constructors cannot be suppressed by a `-name' alias. +Note that if you alias one or more of the constructors of an algebraic +data type the behaviour of `_s_h_o_w' on objects of that type will be +modified in the appropriate way. + +A file which has been %included may itself contain %_i_n_c_l_u_d_e directives, +and so on, to any reasonable depth. A (directly or indirectly) cyclic +%_i_n_c_l_u_d_e is not permitted, however. + +The `?identifier' command can be used to find the ultimate place of +definition of an imported identifier. When aliasing has taken place the +`?identifier' command will give both the current and the original name +of an aliased identifier. If your installed editor is `vi' the +`??identifier' command will open the appropriate source file at the +definition of the identifier. (There is also a command `/find +identifier' which is like `?identifier' but will recognise an alias +under its original name.) + +Every script behaves as though it contained the directive + %_i_n_c_l_u_d_e + +It is therefore illegal to %_i_n_c_l_u_d_e the standard environment explicitly, +as this will lead to huge number of name clashes (because it is now +present twice). As a consequence there is currently no way of aliasing +or suppressing the names in the standard environment. (This will be +fixed in the future by providing a directive for suppressing the +implicit inclusion of .) +------------------------------------------------------------------------ + +%_e_x_p_o_r_t parts + +Any (correct, closed) Miranda script can be %included in another script +(there is no notion of a "module" as something with a different syntax +from an ordinary script). By default the names exported from a script +are all those defined in it, at top level, but none of those acquired by +a %_i_n_c_l_u_d_e of another file. This behaviour can be modified (either to +export more or to export less than the default) by placing a %_e_x_p_o_r_t +directive in the script, specifying a list of `parts' to be exported to +an including file. + +The presence of a %_e_x_p_o_r_t directive in a script has no effect on its +behaviour when it is the current script of a Miranda session - it is +effective only when the script is %included in another. A script may +contain at most one %_e_x_p_o_r_t directive. This can be anywhere in the +script, but to avoid nasty surprises it is advisable to place it near +the top. + +Each `part' listed in the export directive must be one of the following: + identifier (variable or typename) + fileid (in quotes, conventions as described above) + the symbol `+' + -identifier + +Notice that constructors need not (and cannot) be listed explicitly in +an %_e_x_p_o_r_t directive - if you export an algebraic typename, its +constructors are AUTOMATICALLY exported along with it. The consequence +of this is that you cannot use %_e_x_p_o_r_t to create an abstract data type, +by "hiding information" about how an algebraic type was formed. If you +want to create an abstract data type you must use the _a_b_s_t_y_p_e mechanism +- see separate manual entry. + +If a fileid is present in the export list, this must be the name of a +file which is %included in the exporting script, and the effect is that +all the bindings acquired by that %_i_n_c_l_u_d_e statement (as modified by +aliases if present) are re-exported. Allowing fileid's in the export +list is merely a piece of shorthand, which can be used to avoid writing +out long lists of names. + +The symbol `+' is allowed in an export list as an abbreviation for all +the top-level identifiers defined in the current script. + +The default %_e_x_p_o_r_t directive (i.e. that which is assumed if no %_e_x_p_o_r_t +statement is present) is therefore + %_e_x_p_o_r_t + +This will export all the top-level identifiers of the current script, +but not those acquired by %_i_n_c_l_u_d_e directives. + +Finally, the notation `-identifier' is allowed in an export list to +indicate that this identifier NOT to be exported. This is useful if you +have used a fileid or the symbol `+' to abbreviate a list of names, and +wish to subtract some of these names from the final export list. + +An example - the following export statement exports all the top-level +identifiers of the current script, except `flooby'. + %_e_x_p_o_r_t + -flooby + +The order of appearance of the items in an export list is of no +significance, and repetitions are ignored. A negative occurrence of an +identifier overrides any number of positive occurrences. + +It is possible to find out what names are exported from a given Miranda +script (or scripts) by calling, from UNIX, the command + `mira -exports files' (the extension `.m' will be added to each file +name if missing). This will list (to stdout) for each file the exported +names together with their types. +------------------------------------------------------------------------ + +_S_o_m_e_ _e_x_a_m_p_l_e_s + +(i) There are two scripts, called "liba.m" and "libb.m" say, containing +useful definitions. For convenience we wish to combine them into a +single larger library called say, "libc.m". The following text inside +the file "libc.m" will accomplish this. + + %_e_x_p_o_r_t "liba" "libb" + %_i_n_c_l_u_d_e "liba" + %_i_n_c_l_u_d_e "libb" + +You will notice that when "libc.m" is compiled, this does NOT cause +recompilation of "liba.m" and "libb.m" (see section on separate +compilation - the compiler is able to create an object code file for +"libc.m", called "libc.x", by combining "liba.x" and "libb.x" in an +appropriate way). This economy in recompilation effort is one reason +why %_i_n_c_l_u_d_e is a better mechanism than the simpler textual directive +%_i_n_s_e_r_t (see section on compiler directives). + +We could if we wished add some definitions to "libc.m" - if the +corresponding names are added to the %_e_x_p_o_r_t statement these bindings +will then be exported along with those of the two sublibraries. Of +course if we don't add the names of the locally defined objects to the +%_e_x_p_o_r_t directive they will be `private definitions' of "libc.m", not +visible to includors. + +Recall that if no %_e_x_p_o_r_t is directive is present, then ONLY the +immediate definitions (if any) of "libc.m" will be exported. So a +script which contains only %_i_n_c_l_u_d_e directives and no %_e_x_p_o_r_t cannot be +usefully %included in another script (it is however perfectly acceptable +as a current script). + +(ii) [More technical - omit on first reading] + Our second group of examples is chosen to bring out some issues which +arise when exporting types between scripts. Suppose we have the +following script, called "trees.m" + + tree * ::= NILT | NODE * (tree *) (tree *) + reflect :: tree *->tree * + reflect NILT = NILT + reflect (NODE a x y) = NODE a(reflect y)(reflect x) + +(a) If in another script we write `%_i_n_c_l_u_d_e "trees"', the following +bindings will be imported - tree NILT NODE reflect. Now suppose we +modify the "trees.m" by placing in it the following directive - `%_e_x_p_o_r_t +reflect'. When the modified "trees.m" script is included in another, we +will get the following error message from the compilation of the +including script: + + MISSING TYPENAME + the following type is needed but has no name in this scope: + 'tree' of file "trees.m", needed by: reflect; + typecheck cannot proceed - compilation abandoned + +Explanation - it is illegal to export an identifier to a place where its +type, or any part of its type, is unknown. In this situation we call +reflect a `type-orphan' - it has lost one of its parents! + +(b) Readoption of a type-orphan (a more subtle example). Assuming the +"trees.m" script in its original form as above, we construct the +following file "treelib.m" + + %_e_x_p_o_r_t size + %_i_n_c_l_u_d_e "trees" + size :: tree *->num + size NILT = 0 + size (NODE a x y) = 1+size x+size y + +If we %_i_n_c_l_u_d_e the above script in another as it stands, we will of +course get a missing typename diagnostic for `size' - consider however +the following script + + %_i_n_c_l_u_d_e "treelib" + %_i_n_c_l_u_d_e "trees" + ... (etc) + +Everything is now ok, because a name for size's missing parent is +imported through another route (the second %_i_n_c_l_u_d_e statement). The +Miranda compiler recognises the `tree' type imported by the second +%_i_n_c_l_u_d_e as being the same one as that referred to inside "treelib.m", +because it originates (albeit via different routes) from the SAME +SOURCEFILE. A `tree' type imported from a different original +sourcefile, even if it had the same constructor names with the same +field types, would be recognised as a different type. + +[Note: the Miranda compiler is always able to recognise when the same +source file is inherited via different routes, including in cases +involving files with multiple pathnames due to the presence of (hard or +symblic) links.] + +[Further note: the lexical directive %_i_n_s_e_r_t (see compiler directives) +should be regarded as making a _t_e_x_t_u_a_l_ _c_o_p_y of the material from the +inserted file into the file containing the %_i_n_s_e_r_t directive - if the +text of a type definition (in ::= or abstype) is copied in this way, the +compiler will regard the %_i_n_s_e_r_t as having created a new type in each +such case, not identical with that in the inserted file.] + +(c) Last example (typeclash). Finally note that that it is illegal for +the same original type to be imported twice into the same scope even +under different names. Consider the following script + + %_i_n_c_l_u_d_e "trees" shrub/tree Leaf/NILT Fork/NODE -reflect + %_i_n_c_l_u_d_e "trees" + ... (etc) + +The first %_i_n_c_l_u_d_e taken on its own is perfectly ok - we have imported +the `tree' type, and renamed everything in it by using aliases. However +we have also inherited the `tree' type under its original name, via the +second %_i_n_c_l_u_d_e. The compiler will reject the script with the following +message: + + TYPECLASH - the following type is multiply named: + 'tree' of file "trees.m", as: shrub,tree; + typecheck cannot proceed - compilation abandoned + +The rule that a type can have at most one name in a given scope applies +to both algebraic types and abstract types (it does not apply to synonym +types, because these are not `real' types but mere macro's - you can +have any number of synonyms for `tree' in scope at the same time - as +long as the underlying `real' type has a unique name). + +Typeclashes are illegal in Miranda in order to preserve the following +two principles. (i) In any given scope, each possible type must have a +unique canonical form (obtained by expanding out synonyms, and renaming +generic type variables in a standard way). (ii) Each object of a +`printable type' must have, in any given scope, a unique external +representation (ruling out multiply named constructors). The first +principle is necessary to the functioning of the typechecker, the second +is demanded by the requirement that the function `_s_h_o_w' be referentially +transparent. + diff --git a/miralib/manual/27/4 b/miralib/manual/27/4 new file mode 100644 index 0000000..f34bc3d --- /dev/null +++ b/miralib/manual/27/4 @@ -0,0 +1,116 @@ +_T_h_e_ _%_f_r_e_e_ _d_i_r_e_c_t_i_v_e_ _a_n_d_ _p_a_r_a_m_e_t_r_i_s_e_d_ _s_c_r_i_p_t_s + +It is permitted to construct a script containing definitions which are +dependent on information which will be supplied only when the script is +made the subject of a %_i_n_c_l_u_d_e directive. Such a script is said to be +_p_a_r_a_m_e_t_r_i_s_e_d. This is indicated by the presence in the script of a +directive of the form + + %_f_r_e_e { signature } + +where `signature' is a list of specifications of the identifiers for +which bindings will be provided at %_i_n_c_l_u_d_e time. A script may contain +at most one %_f_r_e_e directive, which must therefore give all the +identifiers on which the script is parametrised. The %_f_r_e_e directive +may appear anywhere in the script, but for clarity it is recommended +that you place it at or near the top. + +For example a script (called "matrices" say) defining the notion of +matrix sum and matrix product, for matrices of as-yet-unspecified +element type, could be written as follows:- + + %_e_x_p_o_r_t matmult matadd + + %_f_r_e_e { elem :: _t_y_p_e + zero :: elem + mult, add :: elem->elem->elem + } + + matrix == [[elem]] + + matadd :: matrix->matrix->matrix + matadd xx yy = [[add a b|(a,b)<-zip2 x y]|(x,y)<-zip2 xx yy] + + matmult :: matrix->matrix->matrix + matmult xx yy = outerprod innerprod xx (transpose yy) + innerprod x y = sum [mult a b|(a,b)<-zip2 x y] + _w_h_e_r_e + sum = foldr add zero + outerprod f xx yy = [[f x y|y<-yy]|x<-xx] + +Note that the identifiers declared under %_f_r_e_e may denote types as well +as values. When we write a %_i_n_c_l_u_d_e directive for the above script we +must provide bindings for all of its free identifiers. The bindings are +given in braces following the pathname (and before the aliases, if any). +Thus:- + + %_i_n_c_l_u_d_e "matrices" {elem==num; zero=0; mult=*; add=+; } + +In the scope of the script containing the above directive the +identifiers `matmult' and `addmult' will be available at type +[[num]]->[[num]]->[[num]] and will behave as if their definitions had +been written using 0, (+), (*) in place of the identifiers zero, add, +mult. + +The order in which the bindings are given is immaterial (it need not be +the order in which the identifiers occurred in the %_f_r_e_e directive) but +a binding must be given for each free identifier of the %included +script. Note that the binding for a type is given using `==' and for a +value using `='. If the types of all the bindings (taken together) are +not consistent with the information given in the free directive of the +%included script, or if any required binding is missing, the compiler +will reject the %_i_n_c_l_u_d_e directive as incorrect. + +The main advantage of a parametrised script is that different bindings +may be given for its free identifiers on different occasions. For +example the same script "matrices" may be invoked with different +bindings to provide a definition of matrix addition and multiplication +over matrices with elements of type bool. Thus:- + + %_i_n_c_l_u_d_e "matrices" {elem==bool; zero=False; mult=&; add=\/; } + +It is even possible to %_i_n_c_l_u_d_e the same parametrised script twice in +the same scope (presumably with different bindings for the free +identifiers) but in this case it will be be necessary to alias apart the +two sets of exported identifiers to avoid a nameclash. So we might add +`b_matadd/matadd b_matmult/matmult' to the above directive if it were +being used in the same script as the previous one. + +_M_i_s_c_e_l_l_a_n_e_o_u_s_ _p_o_i_n_t_s + +By default the identifiers declared %_f_r_e_e in a parametrised script are +not exported from the script. As always this can be overridden by +explicitly listing them in an %_e_x_p_o_r_t directive. + +Free typenames of non-zero arity are declared in the following style. + + %_f_r_e_e { stack * :: _t_y_p_e + table * ** :: _t_y_p_e + ... + } + +The corresponding bindings could be as follows + + %_i_n_c_l_u_d_e ... {stack * == [*]; table * ** == [(*,**)]; ... } + +When a parametrised script exports a locally created typename (other +than a synonym type), each instantiation of the script by a %_i_n_c_l_u_d_e is +deemed to create a NEW type (this is relevant to deciding whether or not +two types are the same for the purpose of readopting a type orphan, see +previous manual section). This is because the compiler assumes that an +abstract or algebraic type defined in a parametrised script will in +general have an internal structure that depends on the free identifiers. + +Finally note that the bindings for the free identifiers of a +parametrised script must always be given EXPLICITLY. For example +suppose we wish to %_i_n_c_l_u_d_e the file "matrices" in a script already +containing a type called `elem' over which we intend to do matrix +multiplication. We must write + + %_i_n_c_l_u_d_e "matrices" {elem==elem; etc. } + +The binding `elem==elem' is not redundant, nor is it cyclic, because the +two `elem's involved refer to two different scopes (on the left of the +binding, that of the includee, and on the right that of the script +containing the directive). + diff --git a/miralib/manual/27/5 b/miralib/manual/27/5 new file mode 100644 index 0000000..22e4753 --- /dev/null +++ b/miralib/manual/27/5 @@ -0,0 +1,132 @@ +_S_e_p_a_r_a_t_e_ _c_o_m_p_i_l_a_t_i_o_n_ _a_n_d_ _`_._x_'_ _f_i_l_e_s + +The Miranda compiler compiles to an intermediate code, based on +combinators. When a Miranda expressions are evaluated in the course of +a session this code is executed by an interpreter. + +Since compilation is a complex process (involving lexical analysis, +parsing, type checking and code-generation, as well as a number of other +minor steps) it is undesirable that the results of compiling a script +should just be "thrown away" at the end of a session. To avoid +unnecessary acts of recompilation the Miranda system maintains an +object-code file in association with each source file containing a +Miranda script. + +For each source file, called say `script.m', the Miranda system will +create an object code file, called `script.x'. No action is required by +the user to keep these files up-to-date, since this is taken care of +automatically by the Miranda system. The .x files are never referred to +directly by the Miranda user, and you should not try to edit them (they +contain binary data). + +You may however safely remove any .x file (if for example you don't wish +it to use up filespace) since this will at worst cause the Miranda +compiler to do some extra work later to recreate it. + +If you select a script as the current script of a Miranda session, and +it has an up-to-date .x file, this will be loaded instead, avoiding +recompilation. If the .x file does not exist, or _a_n_y_ _ _r_e_l_e_v_a_n_t_ _ _s_o_u_r_c_e_ +_f_i_l_e_ _h_a_s_ _b_e_e_n_ _m_o_d_i_f_i_e_d since the .x file was created, the script will be +recompiled (and a side effect of your having selected this source file +as the current script will be to bring into existence an up-to-date .x +file for it). + +[Inductive definition - source file B is `relevant' to source file A iff +file A %inserts or %includes B or any file to which B is relevant. For +a discussion of `%include' and the other library directives see manual +sections on `The Library Mechanism'.] + +Note that compiling a script containing %include statements will have +the side effect of triggering subsidiary compilation processes for any +relevant source files which have been modified since their corresponding +.x file was created. Users familiar with the UNIX program `make' will +recognise this process as essentially the same as that which happens +when a `makefile' is obeyed. In the case of Miranda however, the `make' +process is fully automated by being built into the compiler. + +_M_o_r_e_ _a_d_v_a_n_c_e_d_ _i_n_f_o_r_m_a_t_i_o_n + +If you want to check that a given Miranda script has an up-to-date +object code file _w_i_t_h_o_u_t entering a Miranda session, this can be +accomplished from UNIX by calling mira with a special flag, thus + mira -make script.m + +will force the existence of an up-to-date `script.x', performing all +(and only) those compilations which are necessary. Any number of source +files can be given after the -make flag (and as usual if a `.m' +extension is omitted it will be added automatically). + +Example:- to make sure every Miranda source file in your current +directory has an up-to-date object code file, say `mira -make *.m'. + +Applying mira -make to a `.x' file is equivalent to applying it to the +corresponding `.m' file. So another way to make sure everything in your +current directory is up-to-date is to say `mira -make *.x'. This has +the advantage that it will also remove any `.x' files whose `.m' files +no longer exist. + +In the best UNIX tradition mira -make does its work silently unless +something is wrong. If the source files are all correct closed scripts +with up-to-date `.x' files, mira -make says nothing at all. If +recompilations are necessary it informs you which source files are being +compiled, and, as a last step, the names of any scripts which contain +errors or undefined names are listed, to stdout. + +The exit status of a `mira -make' (relevant if you are a shell +programmer, or wish to include a `mira -make' command in a makefile for +a larger setup) is as follows. If (AFTER any necessary recompilations +have been performed) all the source files have up-to-date `.x' files, +and do not contain any syntax errors, type errors, or undefined names +(these facts are recorded in .x files) the exit status will be zero +(=ok), otherwise it will be 1. + +It is possible to find out what names are exported from one or more +Miranda scripts without entering a Miranda session by using the command + mira -exports files +(as always the `.m' extension is added automatically to each filename, +if missing). This command first calls `mira -make' on each file, to +make sure everything is uptodate, and then lists to standard output the +exported names together with their types (one per line). If more than +one file is specified each group of names will be preceded by the name +of the file to which they appertain. + +Note that the export profile of a script includes information about its +free identifiers (if any). + +It is also possible to find out the names of all files on which a given +set of Miranda scripts depend, via %include and %insert statements, by +using the command + mira -sources files +This lists to standard output, one per line, the names of all relevant +source files. The standard environment, , is always omitted +from the list. + +_E_f_f_e_c_t_ _o_f_ _`_m_v_'_ _a_n_d_ _`_r_m_' + Finally we note a couple of points about the behaviour of Miranda .x +files under applications of mv and rm to their corresponding sources. + +A `.x' file records (inter alia) the names of all relevant source files +relative to the directory in which it is stored, together with their +`date and time last modified'. Note that the UNIX command `mv' does not +alter the time-last-modified of the file being moved. So it is possible +when moving a miranda source file (or a group of interdependant source +files) from one directory to another to save mira the bother of +recompiling them, simply by moving all the relevant `.x' files into the +new directory along with the sources. (This doesn't work however if you +change the name of any of the source files during the move.) + +[Note that `tar' has the same property, so the up-to-date-ness of +Miranda .x files is preserved across a tape dump.] + +If you use `rm' to remove a Miranda source file, the next time you +invoke mira with the (now non-existent) file as its current script, it +will promptly remove the corresponding `.x' file. The logic of this is +as follows:- `.x' files must be kept up-to-date with their sources, and +the way to make a `.x' file up-to-date with a non-existent source is to +make it too non-existent. As a consequence it is not possible to send +someone a Miranda object code file without the corresponding source +(mira will delete it as soon as they try to use it!). + +From some points of view this last feature might be regarded as a bug - +a way round it may be provided in a later release of the Miranda system. + diff --git a/miralib/manual/27/contents b/miralib/manual/27/contents new file mode 100644 index 0000000..f9db2c8 --- /dev/null +++ b/miralib/manual/27/contents @@ -0,0 +1,8 @@ +_T_h_e_ _M_i_r_a_n_d_a_ _L_i_b_r_a_r_y_ _M_e_c_h_a_n_i_s_m + + 1. Syntax of library directives + 2. The %include directive (basic information) + 3. About library directives (more detailed information) + 4. The %free directive and parametrised scripts + 5. Separate compilation and `.x' files + diff --git a/miralib/manual/28 b/miralib/manual/28 new file mode 120000 index 0000000..d0e6aa8 --- /dev/null +++ b/miralib/manual/28 @@ -0,0 +1 @@ +../stdenv.m \ No newline at end of file diff --git a/miralib/manual/29 b/miralib/manual/29 new file mode 120000 index 0000000..2475c35 --- /dev/null +++ b/miralib/manual/29 @@ -0,0 +1 @@ +29.m \ No newline at end of file diff --git a/miralib/manual/29.m b/miralib/manual/29.m new file mode 100644 index 0000000..9479de6 --- /dev/null +++ b/miralib/manual/29.m @@ -0,0 +1,88 @@ +> || _L_i_t_e_r_a_t_e_ _s_c_r_i_p_t_s_ _(_a_n_ _a_l_t_e_r_n_a_t_i_v_e_ _c_o_m_m_e_n_t_ _c_o_n_v_e_n_t_i_o_n_) + +The standard comment convention for Miranda scripts is that anything +rightwards from a pair of vertical bars to the end of a line is taken to +be comment and ignored by the compiler, thus + ||This is a comment + +Everything else in the script is taken to be formal program text. An +inverted style of commenting is also available in Miranda, permitting +the construction of a "literate script" (the name is taken from +Professor Donald Knuth's idea of "literate programming"). In a literate +script EVERYTHING is assumed to be comment, except for lines marked with +the formalising symbol '>' in column 1. For example the following lines + +> fac 0 = 1 +> fac (n+1) = (n+1)*fac n + +would be taken as formal program text - and could be preceded and/or +followed by some narrative explaining what the factorial function is and +why we define it in this way. + +To minimise the danger that you will accidentally omit the '>" from one +line of your formal text without the compiler noticing that something is +wrong, the following additional rule applies to Miranda literate scripts +- whenever a group of lines of formal program text is preceded or +followed by some lines of "narrative", the two types of text must be +separated by at least one blank line. You will see that this has been +done for the definition of factorial given above. (Definition - a +"blank line" is one containing only white space.) + +Within the formal sections of a literate script the standard comment +convention still works. For example + +> result = sum [fac n | n <- [1..50]] ||NB this is a large number! + +The compiler takes a decision on which comment convention applies by +looking at the first line of a script. If this has a '>' in column 1, +then it is a literate script, otherwise the compiler assumes it is a +conventional script. Typically the first line of a literate script will +just be a comment, eg + +> ||This is a literate script + +In fact this manual section is a legal Miranda script, defining `fac' +and `result' (see first line). + +An alternative convention is based on the name of the file - if this +ends in `.lit.m' then it is assumed to be a literate script, +independently of the form of the first line. This makes it possible to +have literate scripts which begin in `narrative' mode. + +As an aid to maintaining good layout in literate scripts, a simple text +formatting program, called `just' (short for justify), is supplied with +the Miranda system. This leaves untouched the formal sections of the +script and formats the narrative parts to specified width (default 72). + +There is a UNIX manual page for `just' which gives details of its +behaviour. Note that `just' is a general purpose text formatting tool +and is not in any way Miranda-specific. + +As an additional aid to the use of document preparation tools in +conjunction with Miranda scripts, the Miranda compiler will recognise +underlined keywords. This applies both to reserved words, such as `_d_i_v' +and `_m_o_d' and to directives such as `_%_e_x_p_o_r_t' (underlining of the +initial `%' is optional). The style of underlining accepted is +`backspace-underline-character' as generated by nroff/troff. It will +also recognise the underlined symbols _> and _< as being equivalent to >=, +<= respectively. This works in both literate scripts and scripts using +the standard comment convention. + +_U_s_i_n_g_ _L_a_T_e_X_ _w_i_t_h_ _M_i_r_a_n_d_a_ _l_i_t_e_r_a_t_e_ _s_c_r_i_p_t_s + Because of the `.lit.m' convention it is possible for a file to be both +a Miranda script and a LaTeX source file. In such a case the sections +of formal Miranda text (recognised by the Miranda compiler by the `>' in +column 1) will be surrounded by the LaTeX commands + \begin{verbatim} + + \end{verbatim} + A similar arrangement can be made for troff. + +[The 1989 distribution included a program, mtotex, for using mira with +LaTeX, but this no longer works and has been removed - DT] + +_A_c_k_n_o_w_l_e_d_g_e_m_e_n_t_s + The '>' inverse-comment convention (and the "blank line" rule) are due +to Richard Bird and Philip Wadler of Oxford University Programming +Research Group, and were first used in their language "Orwell". + diff --git a/miralib/manual/3 b/miralib/manual/3 new file mode 100644 index 0000000..46206c7 --- /dev/null +++ b/miralib/manual/3 @@ -0,0 +1,55 @@ +_A_b_o_u_t_ _t_h_i_s_ _r_e_l_e_a_s_e + +This is Miranda release two of October 1989 rereleased thirty years on +as open source - as historical record and in the hope that it may still +be useful. Originally released in 1985, Miranda was the first widely +used non-strict, purely functional language with polymorphic typing and +had a significant influence on the development of the field. + +The source code has been revised to the current C standard (C11) so it +will compile for both 32 and 64 bit platforms. Various bugs have been +fixed and some features added (see the Changes section of the manual) +but the Miranda language and main features of the system interface +remain unchanged. The manual has been revised in places for clarity and +to remove out of date material. + +The online manual pages are primarily intended to document the system at +the level required by someone who already knows quite a lot about +programming languages and has some previous exposure to functional +programming. There is a certain amount of tutorial material, but if you +are a beginner to functional programming you may find parts of the +manual hard to follow, and will need to seek help elsewhere. + +The following paper gives a convenient summary of the main features of +Miranda: + D. A. Turner "An Overview of Miranda", SIGPLAN Notices, December 1986. +A copy of this paper is included in the manual pages, but this and other +information about Miranda can be found on the world wide web at + miranda.org.uk + +Miranda has two available text books + +1. Simon Thompson "Miranda: the Craft of Functional Programming", + Addison-Wesley, 470 pages, 1995. + ISBN 0-201-42279-4 (Paperback) +A webpage for the book by the author is at + www.cs.kent.ac.uk/people/staff/sjt/Miranda_craft/ +or follow the link under BOOKS at miranda.org.uk. + +2. Chris Clack, Colin Myers & Ellen Poon "Programming with Miranda", + Prentice Hall, 312 pages, 1995. + ISBN 0-13-192592-X +The rights in this book have reverted to the authors who have made it +available online - follow link under BOOKS at miranda.org.uk. + +There were two other texts, both now out of print, but there may be +copies in a library or with second hand book sellers. + + Richard Bird & Philip Wadler "An Introduction to Functional Programming", + Prentice Hall, 293 pages, March 1988. + This used a mathematical notation, quite closely based on Miranda but + equally suitable for use with other functional languages. + + Ian Holyer "Functional Programming with Miranda" + Pitman, 215 pages, 1991 + diff --git a/miralib/manual/30 b/miralib/manual/30 new file mode 100644 index 0000000..b28e6ee --- /dev/null +++ b/miralib/manual/30 @@ -0,0 +1,261 @@ +_S_o_m_e_ _g_u_i_d_e_l_i_n_e_s_ _o_n_ _g_o_o_d_ _p_r_o_g_r_a_m_m_i_n_g_ _s_t_y_l_e_ _i_n_ _M_i_r_a_n_d_a + +We give here a series of suggested guidelines for good programming style +in Miranda. The list is not meant to be exhaustive. These rules are +also not intended to be followed in all cases, regardless of conflicting +considerations. That is why they are only suggestions for good style +and not grammar rules. + +_A_v_o_i_d_ _t_h_e_ _i_n_d_i_s_c_r_i_m_i_n_a_t_e_ _u_s_e_ _o_f_ _r_e_c_u_r_s_i_o_n + A Miranda script that consists of large number of functions which call +each other in an apparently random fashion is no easier to understand +than, say, a piece of FORTRAN code which is written as a rat's nest of +GOTO statements. An excessive reliance on recursion (especially mutual +recursion) can be an indication of a weak programming style. Some +pointers: + +Use list comprehensions, `..' lists, and library functions, in +preference to ad-hoc recursion. For example it is probably clearer to +define factorial by writing + fac n = product[1..n] + +than to define it from first principles, as + fac 0 = 1 + fac (n+1) = (n+1) * fac n + +and to define the cartesian product of two lists by a list +comprehension, thus + cp x y = [(a,b)|a<-x;b<-y] + +is certainly a lot clearer than the recursive definition, + cp (a:x) y = f y ++ cp x y + where + f (b:y) = (a,b): f y + f [] = [] + cp [] y = [] + +The standard environment contains a number of useful list processing +functions (eg map filter reverse foldr foldl) with whose properties it +is worth becoming familiar. They capture common patterns of recursion +over lists, and can often be used to simplify your code, and reduce the +reliance on `ad-hoc' recursion. Programs using list comprehensions and +standard functions are also likely to run faster (on the current +implementation) than equivalent programs using ad-hoc recursion. + +The standard environment is only a basic collection of useful general +purpose functions. As you get used to programming in Miranda you will +probably begin to discover other useful functions that express common +patterns of recursion (perhaps over data structures other than lists). +It is a good practice to collect such functions in libraries (together +with some explanations of their properties) so that you can reuse them, +and share them with others. Not all of them will survive the test of +time, but it cannot hurt to experiment. + +To cause the definitions from such a library to be in scope in another +script you would use a `%include' directive (see manual section on +library directives). + +_A_v_o_i_d_ _u_n_n_e_c_e_s_s_a_r_y_ _n_e_s_t_i_n_g_ _o_f_ _d_e_f_i_n_i_t_i_o_n_s + Scripts that get deeply nested in where-clauses are harder to +understand, harder to reason about formally, harder to debug (because +functions defined inside where's cannot be exercised seperately) slower +to compile, and generally more difficult to work with. + +A well structured script will consist of a series of top-level +definitions, each of which (if it carries a where-clause at all) has a +fairly small number of local definitions. A third level of definition +(where inside where) should be used only very occasionally. [And if you +find yourself getting nested four and five levels deep in block +structure you can be pretty sure that your program has gone badly out of +control.] + +A function should normally be placed inside a where clause only if it is +logically necessary to do so (which will be the case when it has a free +variable which is not in scope outside the where clause). If your +script consists, of say six functions, one of which solves a problem and +the other five of which are auxiliary to it, it is probably not a good +style to put the five subsidiary functions inside a where clause of the +main one. It is usually better to make all six top level definitions, +with the important one written first, say. + +There are several reasons for this. First that it makes the program +easier to read, since it consists of six separate chunks of information +rather than one big one. Second that the program is much easier to +debug, because each of its functions can be exercised separately, on +appropriate test data, within a Miranda session. Third that this +program structure is more robust for future development - for example if +we later wish to add a second `main' function that solves a different +problem by using the same five auxiliary functions in another way, we +can do so without having to restructure any existing code. + +There is a temptation to use `where' to hide information that is not +relevant at top-level. This may be misguided (especially if it leads to +code with large and complex where-clauses). If you don't wish all of +your functions or data structures to be "visible" from outside, the +proper way to do this is to include a `%export' directive in the script. + +Note also that (in the current implementation) functions defined inside +a "where" clause cannot have their types explicitly specified. This is +a further reason to avoid putting structure inside a where clause that +does not logically have to be there. + +_S_p_e_c_i_f_y_ _t_h_e_ _t_y_p_e_s_ _o_f_ _t_o_p_ _l_e_v_e_l_ _i_d_e_n_t_i_f_i_e_r_s + The Milner type discipline is an impressive advance in compiler +technology. It is also a trap for the unwary. The fact that the +Miranda compiler will accept several hundred lines of code without a +single type specification, and correctly infer the types of all the +identifiers does NOT mean that it is sensible to write code with no type +information. (Compare: compilers will also accept large programs with +no comments in, but that doesn't make such programs sensible.) + +For other than fairly small scripts it is good style to insert an +explicit specification of the type of any top level identifier whose +type is not immediately apparent from its definition. Type +specifications look like this + ack::num->num->num +says that `ack' is a function taking two numbers and returning a number. +A type specification can occur anywhere in a script, either before or +after the definition of the corresponding identifier, but common sense +suggests that the best place for it is just before the corresponding +definition. + +If in doubt it is always better to put in a type specification than to +leave it out. The compiler may not need this extra type information but +human beings definitely do. The extra type information becomes +particularly important when your code reaches the level of complexity at +which you start to make type errors. + +If your script contains a type error it is unreasonable to expect the +compiler to correctly locate the real source of the error in the absence +of explicit type declarations. A type error means different parts of +your code are inconsistent with one another in their use of identifiers +- if you have not given the compiler any information about the intended +use of an identifier, you cannot expect it to know which of several +conflicting uses are the `wrong' ones. In such a case it can only tell +you that something is wrong, and indicate the line on which it first +deduced an inconsistency - which may be many lines later than the `real' +error. Explicit type declarations make it much more likely that the +compiler will spot the `real error' on the line where it actually +occurs. + +Code containing explicit type information is also incomparably easier +for other people to read. + +_U_s_e_ _s_a_f_e_ _l_a_y_o_u_t + This is a point to do with the operation of the offside rule. It is +most easily explained by means of an example. Consider the following +definition, here assumed to be part of a larger script + + hippo = (rhino - swan)/piglet + _w_h_e_r_e + piglet = 17 + rhino = 63 + swan = 29 + +Some time after writing this we carry out a global edit to expand +`hippo' to `hippopotamus'. The definition now looks like this. + + hippopotamus = (rhino - swan)/piglet + _w_h_e_r_e + piglet = 17 + rhino = 63 + swan = 29 + +the where-clause has become offside, and the definition will no longer +compile. Worse, it is possible (with a little ingenuity) to construct +examples of layout where changing the length of an identifier will move +a definition from one level of scope to another, so that the script +still compiles but now has a different meaning!!! Replacing an +identifier by a shorter one can cause similar difficulties with layout. + +The layout of the `hippo' definition was unsafe, because the level of +indentation depended on the length of an identifier. There are several +possible styles of `safe' layout. The basic rule to follow is: + + Whenever a right hand side goes on for more than one line + (because it consists of a set of guarded cases, or because it + carries a where clause, or just because it is an expression too + big to fit on one line), you should take a newline BEFORE + starting the rhs, and indent by some standard amount (not + depending on the width of the lhs). + +There are two main styles of safe layout, depending on whether you take +the newline before or after the `=' of the definition. Here are two +possible safe layouts for the `hippo' definition + + hippo = + (rhino - swan)/piglet + _w_h_e_r_e + piglet = 17 + rhino = 63 + swan = 29 + + hippo + = (rhino - swan)/piglet + _w_h_e_r_e + piglet = 17 + rhino = 63 + swan = 29 + +The reason that either style can be used is that the boundary, for +offside purposes, of a right hand side, is set by the first symbol of +the rhs itself, and not by the preceding `=' sign. + +Both of these layouts have the property that the parse cannot be +affected by edits which alter the lengths of one or more identifiers. +Either of these layout styles also have the advantage that successive +levels of indentation can move to the right by a fixed step - this makes +code easier to read and lessens the danger that your layout will `fall +off' the right hand edge of the screen (although if you follow the +advice given earlier about avoiding deeply nested block structure this +is in any case unlikely to be a problem). + +It would be convenient if there was a program for reformatting Miranda +scripts with a standard layout. Apart from ensuring that the layout was +`safe' in the above sense, it might make it easier for people to read +each other's code. A layout program of this kind may be provided in +later releases of the system. + +Acknowledgement: The `hippopotamus' example (and the problem of unsafe +layout) was first pointed out by Mark Longley of the University of Kent. + +_W_r_i_t_e_ _o_r_d_e_r_ _i_n_d_e_p_e_n_d_e_n_t_ _c_o_d_e + When defining functions by pattern matching it is best (except in a few +cases where it leads to real clumsiness of expression) to make sure the +patterns are mutually exclusive, so it does not matter in what order the +cases are written. + +For the same reason it is better style to use sets of guards which are +composed of mutually exclusive boolean expressions. The keyword +`otherwise' sometimes helps to make this less painful. + +By way of illustration of some of the issues here is a definition of a +function `merge' which combines two already sorted lists into a single +sorted result, eliminating duplicates in the process + merge [] y = y + merge (a:x) [] = (a:x) + merge (a:x) (b:y) + = a:merge x (b:y), if ab + = a:merge x y, otherwise + +Note the use of mutually exclusive sets of patterns (it was tempting to +write `merge x [] = x' as the second case, but the above is probably +better style). + +A related issue to these is that where a function is not everywhere +defined on its argument type, it is good practice to insert an explicit +error case. For example the definition given in the standard +environment for `hd', the function which extracts the first element of a +list, is + hd (a:x) = a + hd [] = error "hd []" + +Of course if a function is applied to an argument for which no equation +has been given, the Miranda system will print an error message anyway, +but one advantage of putting in an explicit call to `error' is that the +programmer gets control of the error message. The other (and perhaps +main) advantage is that for someone else reading the script, it +explicitly documents the fact that a certain use of the function is +considered an error. + diff --git a/miralib/manual/31/1 b/miralib/manual/31/1 new file mode 100644 index 0000000..388cc0d --- /dev/null +++ b/miralib/manual/31/1 @@ -0,0 +1,92 @@ +_I_n_p_u_t_ _f_r_o_m_ _U_N_I_X_ _f_i_l_e_s_ _e_t_c_. + +The following Miranda functions provide an interface to the UNIX file +system from within Miranda expressions: + + read :: [char]->[char] +This takes a string valued argument, which it treats as a UNIX pathname, +and returns the contents of the file or device of that name, also as a +string (i.e. as a list of characters). There is no end-of-file +character, the termination of the file is indicated simply by the end of +the list of characters. The Miranda evaluation terminates with an error +message if the file does not exist or the user does not have read +permission for it. + +A special case - the notation `$-' denotes the contents of the standard +input, as a list of characters. Note that multiple occurrences of `$-' +always denote a single shared input stream. So for example ($- ++ $-) +reads one lot of data from the terminal and duplicates it. + +(See separate subsection on Input/Output of binary data for the binary +versions readb and $:-) + + filemode :: [char]->[char] +Takes a pathname and returns a string representing the access +permissions of the current process to the file of that name. The string +is empty if the file does not exist, otherwise it is of length four +containing, in order, the following characters - 'd' if the file is a +directory, 'r' if it is readable, 'w' if it is writeable, 'x' if it is +executable. Each character not applicable is replaced by '-'. So for +example "drwx" is the filemode of a directory with all access +permissions, while "-rw-" is the filemode of a normal file with read and +write but no execute permission. + + getenv :: [char]->[char] +Looks up the string associated with a given name in the current UNIX +environment (see man (2) getenv in the UNIX manual system). For example + getenv "HOME" +returns the name of the current home directory. Returns the empty +string if the given name not present in the environment. + + system :: [char]->([char],[char],num) +The effect of `system string' is that a UNIX process is forked off to +execute `string' as a shell command (by `/bin/sh'). The result of the +call to `system' is a triple containing the standard output, error +output, and exit_status, respectively, resulting from the execution of +the UNIX command. (The exit_status of a UNIX command is a number in the +range 0..127, with a non-zero exit status usually indicating some kind +of abnormal event.) Note that inspecting the exit_status will force the +Miranda process to wait until the execution of the shell command has +completed - otherwise the two processes proceed concurrently. + +If the attempt to set up a shell process fails, `system' returns the +result ([],errmess,-1), where errmess is an error message. + +WARNING - the function `system' provides a very general interface to +UNIX. Obviously, this can be abused to cause the evaluation of a +Miranda expression to have side effects on the state of the filing +system. It is not intended to be used in this way - `system' should be +used only to _o_b_t_a_i_n _i_n_f_o_r_m_a_t_i_o_n about the state of the world. If you +wish to change the state of the world, this should be done by placing a +`System' message in your output list (see next manual section). + +Since reading data from the terminal would constitute a side effect, the +background process created by `system' comes into being with its +standard input closed. + +_I_m_p_l_e_m_e_n_t_a_t_i_o_n_ _R_e_s_t_r_i_c_t_i_o_n + `read', `filemode', `getenv', and `system' all require their argument +to be at most 1024 characters long. + +_N_o_t_e_ _o_n_ _s_y_s_t_e_m_ _r_e_a_d_i_n_g_ _f_u_n_c_t_i_o_n_s_ _a_n_d_ _r_e_f_e_r_e_n_t_i_a_l_ _t_r_a_n_s_p_a_r_e_n_c_y + +Although `read', `filemode', `getenv' do not have side effects, they are +not referentially transparent because it cannot be guaranteed that an +expression like + read "file" +will return the same result if evaluated twice. Some external event may +have changed the state of the filing system in the meantime. Clearly +the same problem applies to `system' - consider for example the +expression + system "date" +which gets date-and-time as a string. Evaluating this twice in +succession is unlikely to produce the same result. + +Strictly speaking all calls to `read' and the other functions in this +section ought to be evaluated with respect to the state-of-the-world as +it existed before the evaluation of the given Miranda expression +commenced. Otherwise referentially transparent behaviour cannot be +guaranteed. Enforcing this would appear to require, among other things, +taking a copy of the whole filing system before each Miranda +command-level evaluation. For obvious reasons this is not implemented. + diff --git a/miralib/manual/31/2 b/miralib/manual/31/2 new file mode 100644 index 0000000..9348cc5 --- /dev/null +++ b/miralib/manual/31/2 @@ -0,0 +1,138 @@ +_O_u_t_p_u_t_ _t_o_ _U_N_I_X_ _f_i_l_e_s_ _e_t_c_. + +Since Miranda is a functional language, the evaluation of an expression +cannot in itself cause a side effect on the state of the world. The +side effects occur when the value of the expression is printed. The +value of a command level expression is a list of `system messages', +where the possible forms of message are shown by the following type +declaration, + + sys_message ::= Stdout [char] | Stderr [char] | Tofile [char] [char] | + Closefile [char] | Appendfile [char] | System [char] | + Exit num | Stdoutb [char] | Tofileb [char] [char] | + Appendfileb [char] + +The system `prints' such a list of messages by reading it in order from +left to right, evaluating and obeying each message in turn as it is +encountered. The effect of the various messages is as follows. + + Stdout string +The list of characters `string' is transmitted to the standard output, +which will normally be connected to the user's screen. So for example +the effect of obeying + [Stdout "!!!"] +is that three exclamation marks appear on the screen. + + Stderr string +The list of characters `string' is sent to the standard error output. +[Explanation to those unfamiliar with UNIX stream philosophy: all normal +UNIX processes come into existence with a standard input stream, and two +output streams, called standard out and standard error respectively. +Under normal circumstances standard error and standard out are both +connected to the users screen, but in principle they could be connected +to different places.] + + Tofile fil string +The characters of the string are transmitted to the file or device whose +UNIX pathname is given by `fil'. Successive `Tofile' messages to the +same destination are appended together (i.e. the first such message +causes the file to be opened for writing, and it remains open until the +end of the whole message list). Note that opening a file for output +destroys its previous contents (unless preceded by an `Appendfile' +message, see below). + + Closefile fil +The stream which has been opened to the file `fil' (presumably the +subject of some previous `Tofile' messages) is closed. If `fil' was not +in fact open this command has no effect (i.e. is harmless). All +open-for-output streams are automatically closed at the end of a +message-list evaluation, so it is only necessary to invoke `Closefile' +explicitly if you wish to terminate output to given file during a +message-list evaluation. (One reason why you might want to do this is +so as not to have too many output files open at one time, since many +UNIX systems place a limit on the number of streams which a process can +have.) + + Appendfile fil +If obeyed before any `Tofile' messages to destination `fil', causes the +file to be opened in `append-mode', so its previous contents are added +to, instead of being replaced. + +See separate subsection on Input/Output of binary data for explanation +of the binary versions Stdoutb, Tofileb, Appendfileb. + + System string +Causes `string' to be executed as a shell command (by `/bin/sh') at this +point in time. Enables arbitrary UNIX commands to be invoked from +within a Miranda output list. The shell process comes into being with +its streams (standard input, standard output, standard error) inherited +from the Miranda process. + + Exit num +Causes the UNIX process evaluating the message list to terminate at this +point with exit status `num' (an integer between 0 and 127). The +remaining messages in the list (if any) are discarded. The exit status +of a Miranda evaluation which terminates other than by a call to Exit +will be 0 if it terminates successfully or 1 if it encounters a runtime +error. The exit status is only relevant if you are using Miranda to +implement a stand-alone UNIX command (see separate manual page about +this). + +[Explanation: the exit status of a UNIX command is a one byte quantity +which is communicated back to the calling shell and can be tested by it +- the usual convention is that 0 exit status means all ok, anything else +means something was amiss. If you are not into shell programming you +can safely ignore the whole issue.] + +_T_h_e_ _d_e_f_a_u_l_t_ _o_u_t_p_u_t_ _m_e_c_h_a_n_i_s_m + +We have stated above that the value of a command level expression is +expected to be of type `[sys_message]'. + +If it is not of that type mira applies the following rules: + (i) if the value is of type [char] the characters are directed to +standard output, as if you had written [Stdout (expr)]. + (ii) if it is of another type, show is first applied to convert it to +type [char], so it is as if you had written [Stdout (show (expr))] + +This explains how the Miranda system is able to function in its standard +`desk-calculator' mode. + +Be aware that if is not loaded (because you invoked mira with +-stdenv, and the script does not explicitly %include there will +be no type sys_message and only the default output mechanism will be +available. + +_O_u_t_p_u_t_ _r_e_d_i_r_e_c_t_i_o_n + +A Miranda command of the form + exp &> pathname +causes a background process to be set up for the evaluation of `exp', +with both the standard output and the standard error output of the +process redirected to `pathname'. If `exp' is of type [sys_message], +the destination of `Tofile' messages are not affected by the global +redirection - only messages which would otherwise have gone to the +screen are sent to `pathname'. + +If two (blank separated) pathnames are given after the `&>', standard +output is redirected to the first file and standard error to the second. +Thus: + exp &> outfil errfil + +If the `&>' is replaced by a `&>>', instead of overwriting the previous +contents, the relevant output is appended to the end of the file. Thus: + exp &>> pathname(s) +As with the `&>' command, either one or two pathnames can be given, +depending on whether you wish standard error to be merged with standard +out, or separated from it. + +Note that a background process created by a `&>' or `&>>' command has no +standard input - if the expression contains `$-', the latter will +evaluate to `[]'. + +_I_m_p_l_e_m_e_n_t_a_t_i_o_n_ _R_e_s_t_r_i_c_t_i_o_n_s + Arguments representing pathnames (to Tofile, Appendfile, Closefile) are +restricted to 1024 characters in length - pathnames longer than this +cause an error message. The shell command supplied to System is also +restricted to 1024 characters in length. + diff --git a/miralib/manual/31/3 b/miralib/manual/31/3 new file mode 100644 index 0000000..1746682 --- /dev/null +++ b/miralib/manual/31/3 @@ -0,0 +1,42 @@ +_R_e_a_d_i_n_g_ _w_i_t_h_ _i_n_t_e_r_p_r_e_t_a_t_i_o_n_ _(_`_r_e_a_d_v_a_l_s_'_ _a_n_d_ _`_$_+_'_) + +There is a function _r_e_a_d_v_a_l_s which takes a string representing a UNIX +pathname, and returns a list of values found in the file of that name. +The values may be represented by arbitrary Miranda expressions, written +one per line. Blank lines, and Miranda style comments (||...) are +ignored. If the input file appears to be a teletype, _r_e_a_d_v_a_l_s reacts to +syntactically incorrect or wrongly typed data by prompting the user to +repeat the line, and such bad values are omitted from the result list. +If the input file does not appear to be a teletype, bad data causes +readvals to abort with an error message. + +Note that, similarly to _s_h_o_w + (i) _r_e_a_d_v_a_l_s is a reserved word, not an identifier. + (ii) the context in which it is used must be such as to determine its +type monomorphically. Extra type specifications may be needed in the +script to meet this condition. + +Here is a simple example of how _r_e_a_d_v_a_l_s might be used in a script + x :: [num] + x = readvals "data" +The file `data' should contain expressions of type num (one per line). + +The _r_e_a_d_v_a_l_s function provides Miranda with a simple form of data +persistence - data can be written to a file (e.g. using `_s_h_o_w') and read +back using _r_e_a_d_v_a_l_s in a later session. Data objects saved in this way +must of course be finite. Notice also that if you wish to save data +containing functions, you will have to set up some special arrangement, +since such data cannot be written out using `_s_h_o_w'. + +Data of abstract type can be written to file using _s_h_o_w and read back +with _r_e_a_d_v_a_l_s - provided that an appropriate show-function was included +in the signature of the abstract type (see manual section on abstract +types). + +Finally note that $+ behaves exactly like an application of _r_e_a_d_v_a_l_s to +the name of the file to which the standard input is connected. For +example + sum $+ +read a sequence of numeric expressions from the keyboard (one per line) +up to the next control-D, and then returns their sum. + diff --git a/miralib/manual/31/4 b/miralib/manual/31/4 new file mode 100644 index 0000000..5378454 --- /dev/null +++ b/miralib/manual/31/4 @@ -0,0 +1,175 @@ +_U_s_i_n_g_ _M_i_r_a_n_d_a_ _t_o_ _b_u_i_l_d_ _e_x_e_c_u_t_a_b_l_e_ _f_i_l_e_s + +FIRST METHOD (using a `magic string') + +Create a file, prog.m say, containing a normal miranda script, but with +first line + #! /usr/bin/mira -exec + +The first two characters must be "#!" followed by an optional space and +the absolute pathname of the miranda interpreter. This may be somewhere +other than /usr/bin/mira, the UNIX shell command "which mira" should +tell you where it is. The flag "-exec" is necessary and no other flags +should be added. (Note "-exec2" can be substituted for "-exec", see +below.) + +The remainder of the file can be any legal miranda script, which may +%include other scripts. Somewhere in the file, or in an included file, +there must be a definition of `main'. When `prog.m' is executed as a +UNIX command, the result will be that `main' is evaluated, using the +same rules as if you had entered it in an interactive session, and the +results sent to standard output. Remember to give the file execute +permission (e.g. by saying `chmod +x prog.m'). + +A command of this form can take data from the terminal. The notation +`$-' can be used anywhere in the second and later lines of the file to +denote the list of characters taken from the standard input. (That is +`$-' behaves like a Miranda identifier of type [char].) + +The command can be invoked with arguments, eg + prog.m fig 23 +and the notation `$*' can be used in the script as a Miranda identifier +of type [[char]] denoting the argument list, with the convention that +the initial (zero'th) argument is the name of the command. So in this +case the value of `$*' would be + ["prog.m","fig","23"] +If there are no arguments, `$*' will be a singleton list containing just +the command name. + +_E_x_p_l_a_n_a_t_i_o_n + The line beginning `#!' is a standard UNIX incantation, called a `magic +string', indicating that the following pathname is an interpreter to be +invoked with the name of the file in which it occurs as argument (see +under `execve' in section 2 of the UNIX manual). The flag "-exec" +instructs the Miranda system to evaluate `main', which can be of any +type. If main is a string this is sent to stdout, if it is of another +printable type `show main' is sent to stdout, or if main is of type +[sys-message] the sequence of I/O commands is executed. + +Examples + Here is the Miranda "hello world" program + #! /usr/bin/mira -exec + main = "hello world\n" + +The following script is a Miranda version of the UNIX `cat' command - if +it is invoked without arguments it simply copies its standard input to +its standard output, otherwise it concatenates the contents of its +argument files to the standard output. + #! /usr/bin/mira -exec + + main = [Stdout $-], _i_f tl $* = [] + = [Stdout (concat(map read(tl $*)))], _i_f badargs=[] + = [Stderr (concat(map errmess badargs))], _o_t_h_e_r_w_i_s_e + badargs = [f|f<-tl $*;~member(filemode f)'r'] + errmess f = f++": cannot access\n" + +See the manual pages on input from UNIX files and output to UNIX files +for the explanation of `read', `filemode' and the constructors Stdout, +Stderr etc. + +The rule that Miranda source files must have names ending in ".m" is not +enforced for "magic" scripts, in keeping with the UNIX convention that +executables require no special suffix. However a magic script whose +name ends in ".m" can also be made the subject of a miranda session. +This is advantageous during development, as individual definitions can +be tested. A first line beginning #! is ignored by the Miranda compiler +which treats it as a comment. In this situation $* has the value [], +since the script was not executed as a command. + +Note also that if your Miranda executable file has the ".m" suffix, a +corresponding ".x" file will be created at its first call, avoiding the +need for mira to recompile it on subsequent calls (unless there has been +an update of the source file). + +Notes + (1) In some UNIX-like systems `execve' places a limit on the total +length of the `magic string'. + (2) Because in many systems (including Linux) `execve' permits at most +one flag in a magic string, mira does not understand a `-lib' flag given +in conjunction with a `-exec' flag. This is a possible source of +difficulty if you keep the miralib directory at a non-standard place. +One way round this is to set environment variable MIRALIB, instead of +using a `-lib' flag. See manual section on flags etc. [To do: more +general mechanism to add other flags to -exec in a magic string - DT] + (3) If called from the UNIX command line, + mira -exec script.m +will find and evaluate `main' in script.m and in this situation you can +combine -exec with other flags, -lib miralib, -heap N, etc preceding the +name of the script. Any additional arguments following script.m will +be found in $*. + +_D_e_b_u_g_g_i_n_g_ _s_t_a_n_d_-_a_l_o_n_e_ _s_c_r_i_p_t_s + As an aid to debugging a variant flag is available: + #!/usr/bin/mira -exec2 + definitions... +The -exec2 flag has the same effect as -exec but runtime errors (only, +not compile time errors) are redirected to file miralog/prog, where prog +is the name of the script. The redirection takes place if a miralog +directory exists in the current working directory and the process +running the script has write permission to it. This is useful for +debugging cgi scripts written in Miranda, particularly in the not +infrequent situation that they compile without errors and seem to work +fine from the command line but fail when invoked by an http call. (You +will need to create a directory miralog in cgi-bin and chown it to +apache, or whatever personality cgi scripts run as). + +SECOND METHOD (using a `here document') + +Create a file ("prog' say) containing the following + + mira [script] <> is in quotation marks, eg + mira [script] <<"!" + stuff + ! +then no substitutions will take place inside the here-document. + +The drawbacks of commands built in this way are two - (a) they have no +way of taking information from the terminal during execution (because +the here-document replaces the standard input) and (b) the method of +access to command line arguments is clumsy. + diff --git a/miralib/manual/31/5 b/miralib/manual/31/5 new file mode 100644 index 0000000..546724d --- /dev/null +++ b/miralib/manual/31/5 @@ -0,0 +1,105 @@ +_H_o_w_ _t_o_ _c_h_a_n_g_e_ _t_h_e_ _d_e_f_a_u_l_t_ _e_d_i_t_o_r + +The Miranda /edit or /e command (see manual page on Miranda command +interpreter) invokes an editor. By default this is the screen editor +"vi", but if you wish to use another editor, this is easily changed. + +The Miranda command + /editor + +reports the editor currently in use by the Miranda system. To change it +to (for example) pico, say + /editor pico + +Alternatively, when next invoking the miranda system from UNIX you can +supply it with a flag requesting a specific editor by name, as follows: + mira -editor pico + +In either case it is only necessary to do this once since the Miranda +system stores this and other information in a file called ".mirarc" in +your home directory - you should not remove or try to edit this file. + +You can select any editor that is installed on your system. If you are +unfamiliar with vi and haven't an editor in mind, the editor pico (if +installed) is particularly easy to use - it has instructions on screen. +Similar are nano (an open source clone of pico) and joe. Other editors +include emacs and gvim - these both open a separate editor window. + +The editor you select will be used by both the /e command and by + ??identifier +which opens the relevant source file at the definition of identifier. + +_M_o_r_e_ _a_d_v_a_n_c_e_d_ _i_n_f_o_r_m_a_t_i_o_n + +The Miranda system is designed to work with an editor which can open a +file at a specified line number. For example to make the editor `vi' +open `file' at line 13, the UNIX command is + vi +13 file +the Miranda system has built in knowledge of this, so if the installed +editor is `vi' and the compiler has found a syntax error in the script, +the `/e' command will open the script at the line containing the error. + +To retain this ability when substituting another editor, the `/editor' +command requires a template for invoking the chosen editor at a given +line number. In this template the line number is represented by the +character `!' and the filename by `%'. For example the full template +for `vi' would be supplied as follows + /editor vi +! % + +If the `%' character does not occur in the template, Miranda will add +the name of the file at the end of the command. So the template for +`vi' could equally well be given as + /editor vi +! +The same formula works for pico, nano, joe. If the editor is one that +starts up its own window, separate from the Miranda session window (gvim +and emacs do this), you will want to make the editor run as a concurrent +process by putting "&" at the end of the command, thus + /editor emacs +! % & +Note that in this case you must include % where the filename goes, +because adding it after the "&" would not make sense. + +In fact Miranda has built in knowledge of vi, pico, nano, joe, emacs and +gvim, so just giving the name of the editor will generate the correct +template in these cases. + +If you install an editor without the capability to be opened at a +specified line number (i.e. you cannot give a template for it +containing the `!' character), the /e command loses its ability to go to +the right place after an error, and the `??' command will be disabled. + +The Miranda system will work without either of these features, but there +is a significant loss of power in the user interface. + +If the installed editor lacks the `open at line number' feature, you may +find it convenient to have the script listed to the screen during +compilation (this feature of the compiler can be switched on and off by +the commands `/list', `/nolist'). As an assistance to naive users, the +Miranda system turns on `/list' for you if the `/editor' command is used +to install an editor without the `open at line number' feature. + +[Pathological case: if the editor command you wish to install contains a +literal `!' or `%' that you don't want replaced, place a backslash +before the relevant ! or %. This protects it from being expanded.] + +_C_h_e_c_k_i_n_g_ _f_o_r_ _s_o_u_r_c_e_ _u_p_d_a_t_e_s + +If during a session changes have been made to any relevant source file, +the Miranda system automatically recompiles the current script and any +other scripts which it directly or indirectly `%includes' and which have +been changed. At a minimum this check is performed after each /edit +command and after each shell escape. + +A mode of operation possible on a windowing system is to keep an editor +window and Miranda session window both open. In this case more frequent +checking is appropriate and you should say /recheck (see 6 "Summary of +remaining commands"). This sets a flag which tells the Miranda +interpreter to check for source file updates before each evaluation, +instead of only after /e and ! commands. But remember that you will +need to save any edits to file before the `mira' session can see them. + +As an assistance to naive users /recheck is automatically turned on if +/editor is used to install an editor template which includes "&", the +symbol used in UNIX shell commands to start a concurrent process. + +Say /norecheck to revert to the default behaviour. + diff --git a/miralib/manual/31/6 b/miralib/manual/31/6 new file mode 100644 index 0000000..d088c79 --- /dev/null +++ b/miralib/manual/31/6 @@ -0,0 +1,38 @@ +_H_o_w_ _t_o_ _a_l_t_e_r_ _t_h_e_ _s_i_z_e_s_ _o_f_ _w_o_r_k_s_p_a_c_e_s + +The Miranda system uses two main internal workspaces called "heap" and +"dic". If either overflows during a session, a self explanatory error +message is given. The sizes of both areas may changed by the user if +required. Any change made is remembered thereafter and for subsequent +sessions until countermanded. + +The heap contains almost all the data structures created both by the +Miranda compiler and the evaluation system. To compile and/or run very +large scripts you may need a bigger heap. To find out (change) the +current size of the heap say + /heap (or /heap newsize e.g. /heap 2000000 ) + +The heap size may also be altered by using a flag (see below). You +should be aware that running Miranda processes with a very large heap +may give you slower responses. + +The dictionary is used to store identifiers and file names by the +Miranda compiler. It is unlikely that you will need to change the size +of the dictionary. The current size of the dictionary can be +ascertained by the command + /dic + +it cannot be changed dynamically, from within the Miranda system. To +alter the dictionary size use a flag (see next para). + +The sizes of either or both areas may be set by flags when invoking the +miranda system. The following shows both possibilities + mira -dic 80000 -heap 2000000 [script] + +Note that the size of the heap is given in `cells' (a cell is 9 bytes, +currently) and the size of the dictionary is in bytes. + +The most recent settings of the workspace sizes are stored in the file +".mirarc" in the users home directory, and automatically carried over to +the next miranda session. + diff --git a/miralib/manual/31/7 b/miralib/manual/31/7 new file mode 100644 index 0000000..ae6b20c --- /dev/null +++ b/miralib/manual/31/7 @@ -0,0 +1,160 @@ +_O_p_t_i_o_n_s_,_ _s_e_t_u_p_ _f_i_l_e_s_ _e_t_c_. + +The full form of the `mira' command is + mira [flags...] [script] +this command causes a Miranda session to be entered with the given file +as current script. If no script is specified a default filename +`script.m' is assumed. The specified file need not yet exist - in this +case you will be starting a Miranda session with an empty current +script. + +Note that `.m' is the standard extension for Miranda language source +files - the mira command always adds the `.m' extension, if missing, to +any filename argument denoting a Miranda script. + +The available options are: + + -lib pathname +Tells mira to find miralib (directory containing libraries, manual pages +etc.) at `pathname'. The default is to look for miralib of same version +number as the program at `/usr/lib/miralib', `/usr/local/lib/miralib' +and `./miralib', in that order. The -lib flag overrides the version +number check. The same effect is obtained by setting an environment +variable MIRALIB, see next manual section. + + -gc +Switches on a flag causing the garbage collector to print information +each time a garbage collection takes place. This flag can also be +switched on and off from within the miranda session by the commands +`/gc', `/nogc'. + + -count +Switches on a flag causing statistics to be printed after each +expression evaluation. This flag can also be switched on and off from +within the miranda session by the commands `/count', `/nocount'. + + -list + -nolist +Switches on (off) a flag causing Miranda scripts to be listed to the +screen during compilation. This flag can also be switched on and off +from within the miranda session by the commands `/list', `/nolist'. + + -nostrictif +Enables the compiler to accept old Miranda scripts with missing +occurrences of the keyword `if' in guard syntax. Probably obsolete but +retained just in case someone needs it. + + -hush + -nohush +The miranda system decides whether or not to give prompts and other +feedback by testing its standard input with `isatty'. If the standard +input does not appear to be a terminal it assumes that prompts would be +inappropriate, otherwise it gives them. In either case this behaviour +can be overriden by an explicit flag ("-hush" for silence, "-nohush" for +prompts etc). This switch is also available from within a miranda +session by the commands `/hush', `/nohush'. + + -dic SIZE +Causes the dictionary (used by the compiler to store identifiers etc.) +to be set up with SIZE bytes instead of the default 24kb. + + -heap SIZE +Causes the heap to be set up with SIZE cells instead of the default +(currently 100k). This can also be done from within the miranda session +by the command `/heap SIZE'. A cell currently occupies 9 bytes. + + -editor name +Causes the resident editor (initially `vi', unless the environment +variable EDITOR was set to something else) to be `name' instead. This +can also be done from within the miranda session by the command `/editor +name'. + + -UTF-8 + -noUTF-8 +Assume the current locale is (is not) UTF-8 overriding environment vars +(version 2.044 and later). + + -stdenv +Run mira without loading the standard environment. Every script that +needs functions from the standard environment will then have to either +explicitly %include or define the required functions for +itself. Not recommended as normal practice since it may have unexpected +consequences (for example I/O will be limited by the absence of type +sys-message). + + -object +Used for debugging the compiler. Modifies behaviour of ?identifier(s) +to show the associated combinator code, which may or may not be +comprehensible as there is no documentation other than the source code. + +_S_P_E_C_I_A_L_ _C_A_L_L_S + In addition the following special calls to `mira' are available which +do not enter a Miranda session but accomplish another purpose, as +described below. + + mira -man +To enter the miranda online manual system directly from the UNIX shell. + + mira -exp +Special call permitting the use of miranda script as a stand-alone UNIX +command. See separate manual page for details. + + mira -log +Same as -exp except that it redirects stderr to a file log/mira.errors, +if log directory exists in the current directory and mira has write +permission to it. + + mira -make [sourcefiles] +Forces a check that all the miranda source files listed have up-to-date +object code files, triggering compilation processes if necessary (see +manual subsection on the library mechanism: separate compilation). + + mira -exports [sourcefiles] +Sends to stdout a list of the identifiers exported (see manual +subsection on library mechanism: separate compilation) from each of the +given miranda source files, together with their types (may also force +recompilation if needed). + + mira -sources [sourcefiles] +Sends to stdout a list of all the Miranda source files on which the +given source files directly or indirectly depend (via %include or +%insert statements), excluding the standard environment . + + mira -version +Gives version information. This information can also be obtained from +within a Miranda session by the command `/version'. + + mira -V +More detailed version information. + +_S_E_T_U_P_ _F_I_L_E_S + +The current settings of _d_i_c, _h_e_a_p and _e_d_i_t_o_r are saved in the file +`.mirarc' in the users home directory, and are thereby carried over to +the next miranda session. The settings of the compiler flag which +controls whether or not source is listed to the screen during +compilation (toggled by the commands _/_l_i_s_t _/_n_o_l_i_s_t during a Miranda +session) and of the flag which controls the frequency of checking for +source updates (toggled by the commands /recheck /norecheck) are also +saved in the users `.mirarc' file. + +The default settings of these entities, which will be picked up by new +users executing `mira' for the first time, are dic 24000 (bytes), heap +100000 (9-byte cells), editor _v_i, nolist, norecheck. The current +settings can be interrogated from a Miranda session by the command +`/settings' or `/s'. + +The defaults can be changed, on a system wide basis, by moving a copy of +a `.mirarc' file containing the desired settings into the `miralib' +directory (normally found at /usr/lib/miralib). The user's local +.mirarc file, once created in his home directory by the first call to +mira, will override the global one, however. + +The behaviour of the `mira' program is also sensitive to the settings of +certain environment variables - see separate manual entry about this. + +_O_U_T_P_U_T_ _B_U_F_F_E_R_I_N_G + Output from the Miranda system to the user's terminal should not be +line buffered, or some things will not work as they are intended. There +is no problem about input being line buffered, however. + diff --git a/miralib/manual/31/8 b/miralib/manual/31/8 new file mode 100644 index 0000000..7b35202 --- /dev/null +++ b/miralib/manual/31/8 @@ -0,0 +1,83 @@ +_E_n_v_i_r_o_n_m_e_n_t_ _v_a_r_i_a_b_l_e_s_ _u_s_e_d_ _b_y_ _M_i_r_a_n_d_a + (This section may be of particular interest to installers and system +administrators) + +The behaviour of the `mira' program is sensitive to the settings of +certain environment variables. + +An alternative location for the miralib directory may be specified by +setting the environment variable "MIRALIB". An explicit -lib flag, if +present, overrides this. + +The first time it is called (i.e. if no .mirarc file is present, either +in the home directory or in miralib) the miranda system picks up the +name of the resident editor from the environment variable EDITOR - if +this is not set it assumes `vi'. + +At startup (version 2.044 and later) `mira' inspects LC_CTYPE or if that +is empty LANG, to determine if it is running in a UTF-8 locale. On +Windows/Cygwin this information is taken from the "user-default ANSI +code page". The flag -UTF-8 or -noUTF-8, if present, overrides. + +If the environment variable RECHECKMIRA is set (to any non-empty string) +the Miranda system rechecks to see if any relevant source files have +been updated, and performs any necessary recompilation, before each +interaction with the user - this is the appropriate behaviour if an (eg +emacs) editor window is being kept open permanently during the Miranda +session. If this environment variable is not set, the check is +performed only after `/e' commands and `!' escapes. + +To decide what shell to use in `!' escapes, mira looks in the +environment variable SHELL (this will normally contain the name of the +user's login shell). If no SHELL is entered in the environment, /bin/sh +is assumed. + +If environment variable MIRAPROMPT is set, its contents will be used as +the session prompt, instead of the default prompt "Miranda " (version +2.044 and later). + +If the environment variable NOSTRICTIF is set (to any non-empty string) +Miranda accepts old scripts with no `if' after the guard comma. + +For displaying pages of the manual mira uses the program entered in the +environment as VIEWER - if this variable is not set the default is +likely to be 'more -d' or (roughly equivalent) 'less -EX'. + +If you set VIEWER to something, you may also need to set an environment +variable RETURNTOMENU. + +RETURNTOMENU=YES prevents another prompt being given after displaying +each section, causing instead an immediate return to contents page. It +should be `YES' if VIEWER is a program that pauses for input at end of +file (eg "less"), `NO' if VIEWER is a program that quits silently at end +of file (eg "more", "less -EX"). + +Finally note that a third environment variable MENUVIEWER can be set to +choose the program used to display contents pages (by default this is +normally 'cat' or 'more'). + +To find the current settings of these display commands enter + ??? +to the "next selection" prompt of the manual system. + +_H_o_w_ _t_o_ _s_e_t_ _a_n_ _e_n_v_i_r_o_n_m_e_n_t_ _v_a_r_i_a_b_l_e_ _i_n_ _y_o_u_r_ _U_N_I_X_ _s_h_e_l_l_: + (Reminder/tutorial information) + +Example, setting the environment variable VIEWER to /usr/local/view + + (i) if you use a Bourne-like shell (sh ksh bash) + say at the UNIX command level (i.e. before calling Miranda) + + export VIEWER=/usr/local/view + + to undo the above say `unset VIEWER', + to make permanent add this line to your .profile or .bashrc + + (ii) if you use a C shell (csh tcsh) + say at the UNIX command level (i.e. before calling Miranda) + + setenv VIEWER /usr/local/view + + to undo the above say `unsetenv VIEWER', + to make permanent add the setenv line to your .login or .cshrc + diff --git a/miralib/manual/31/9 b/miralib/manual/31/9 new file mode 100644 index 0000000..8e6bb2d --- /dev/null +++ b/miralib/manual/31/9 @@ -0,0 +1,54 @@ +_I_n_p_u_t_/_o_u_t_p_u_t_ _o_f_ _b_i_n_a_r_y_ _d_a_t_a + +From version 2.044 Miranda stdenv.m includes a function + readb :: [char]->[char] +and new sys-message constructors + Stdoutb :: [char]->sys_message + Tofileb :: [char]->[char]->sys_message + Appendfileb :: [char]->[char]->sys_message + +These behave similarly to (respectively) read, Stdout, Tofile, +Appendfile but are needed in a UTF-8 locale for reading/writing binary +data (for further explanation see below). In a non UTF-8 locale they do +not behave differently from read, Stdout etc but you might still prefer +to use them for handling binary data, for portability reasons. + +The notation $:- is used for the binary version of the standard input. +In a non UTF-8 locale $:- and $- will produce the same results. It is +an error to access both $:- and $- in the same evaluation. + +_E_x_p_l_a_n_a_t_i_o_n + +The locale of a UNIX process is a collection of settings in the +environment which specify, among other things, what character encoding +is in use. To see this information use `locale' as a shell command. +The analogous concept in Windows is called a "code page". + +UTF-8 is a standard for encoding text from a wide variety of languages +as a byte stream, in which ascii characters (codes 0..127) are +represented by themselves while other symbols are represented by a +sequence of two or more bytes: a `multibyte character'. + +The Miranda type `char' consists of characters in the range (0..255) +where the codes above 127 represent various accented letters etc +according to the conventions of Latin-1 (i.e. ISO-8859-1, commonly used +for West European languages). There are national variants on Latin-1 +but since Miranda source, outside comments and string and character +constants, uses only ascii this does not normally cause a problem. + +In a UTF-8 locale: on reading string/character literals or text files +Miranda has to translate multibyte characters to the corresponding point +in the Latin-1 range (128-255). If the text does not conform to the +rules of UTF-8, or includes a character not present in Latin-1, an +"illegal character" error occurs. On output, Miranda strings are +translated back to UTF-8. + +If data being read/written is not text, but binary data of some kind, +translation from/to UTF-8 is not appropriate and could cause "illegal +character" errors, and/or corruption of data. Whence the need for the +byte oriented I/O functions readb etc, which transfer data without any +conversion from/to UTF-8. + +In a non UTF-8 locale read and readb, Tofile and Tofileb, etc. do not +differ in their results. + diff --git a/miralib/manual/31/contents b/miralib/manual/31/contents new file mode 100644 index 0000000..ef9fdbd --- /dev/null +++ b/miralib/manual/31/contents @@ -0,0 +1,12 @@ +_U_N_I_X_/_M_i_r_a_n_d_a_ _s_y_s_t_e_m_ _i_n_t_e_r_f_a_c_e_ _i_n_f_o_r_m_a_t_i_o_n + + 1. Input from UNIX files etc + 2. Output to UNIX files etc + 3. Reading with interpretation (`_r_e_a_d_v_a_l_s' and $+) + 4. Using Miranda to build UNIX commands + 5. How to change the default editor + 6. How to alter sizes of workspaces + 7. Options, setup files etc + 8. Environment variables used by Miranda + 9. Input/Output of binary data + diff --git a/miralib/manual/32 b/miralib/manual/32 new file mode 100644 index 0000000..a54d084 --- /dev/null +++ b/miralib/manual/32 @@ -0,0 +1,98 @@ +_R_E_C_E_N_T_ _C_H_A_N_G_E_S + +January 2020 (version 2.066) + +The Miranda source code has been revised to conform to the C11 standard +and to run on both 64 and 32 bit platforms. Earlier releases were 32 +bit only. + +December 2019 (version 2.057) + +Miranda type `char' now includes all Unicode characters, which can be +specified by hexadecimal escape codes in char and string constants. For +example '\x5d2' is the Hebrew letter Gimel. + +The lexical syntax of Miranda has been extended to include octal and +hexadecimal numerals - e.g. 0o777 is 511 and 0xffffffff is 4294967295. + +See man section 11 (literals) for details of both the above. + +Functions showoct, showhex :: num->[char] have been added to the +standard environment. + +Data types with "laws", declared obsolete at release two, have finally +gone. Strictness annotations: `!' on fields of an algebraic data type +remain part of the language, see man section 20 (algebraic data types). + +The flag -exp, for executable scripts, has gone and is replaced by +-exec, see man section 31/4 (Using Miranda to build UNIX commands). +This is not backwards compatible (sorry) but the change needed is +trivial. If you have a magic script + #!/usr/bin/mira -exp + expression + definitions... +change it to + #!/usr/bin/mira -exec + main = expression + definitions... +The new mechanism executes `main' wherever it is in the script (whereas +-exp required an expression on the second line). + +_O_l_d_e_r_ _C_h_a_n_g_e_s (in reverse date order) + +September 2009 (version 2.044) + +The environment variable MIRAPROMPT may be set to a string to be used as +the Miranda session prompt instead of the default "Miranda ". + +For reading/writing binary files in UTF-8 locale, stdenv is extended by + readb, Stdoutb, Tofileb, Appendfileb +these behave similarly to + read, Stdout, Tofile, Appendfile +but transfer data as bytes with no conversions from/to UTF-8. See new +manual section 31/9. + +August 2008 (version 2.041, 2.042) + +Miranda now detects if it is in UTF-8 locale and converts from/to UTF-8 +on reading/writing string and char values. + +May 2006 (version 2.032) + +The commands /nostrictif, /strictif to control enforcement of `if' in +guard syntax have gone. The `if' has been part of Miranda's syntax +since 1988. In case there are surviving if-less scripts, you can use + mira -nostrictif +or set the environment variable NOSTRICTIF to any non-empty string. + +New command /recheck makes mira check if any loaded script has been +updated before every evaluation, instead of only after /edit (/norecheck +to disable). Appropriate if an editor window is running concurrently +with the Miranda session window. The setting is remembered for +subsequent sessions. Formerly enabled by setting environment variable +RECHECKMIRA to a non-empty string - that method still works also. + +mira now checks that it has miralib of same version number - exits with +error message otherwise. An explicit mira -lib overrides this +but it is in general inadvisable to run mira with wrong miralib. + +_H_i_s_t_o_r_y_ _o_f_ _M_i_r_a_n_d_a_ _r_e_l_e_a_s_e_s + +1 May 1985 - alpha test, released to University of Kent only. + +October 1985 - beta test (version 0.292 for VAX, 0.293 for SUN) +Distributed to 88 sites. + +April 1987 - release one (version 1.009 or 1.016 or 1.019) +Added literate scripts, library mechanism: %export, %include, (n+k) patterns. +Around 250 sites. + +October 1989 - release two (versions 2.0xx for various machines) +Added unbounded size integers, %free, faster SK reduction m/c +Around 550 sites by mid-90's. + +May 2006 - revised and released as free software (but not open source). + +Nov 2019 - revised and made open source. + +Jan 2020 - revised to C11 standard and made 64 bit compatible. diff --git a/miralib/manual/33 b/miralib/manual/33 new file mode 100644 index 0000000..1d985ce --- /dev/null +++ b/miralib/manual/33 @@ -0,0 +1,4 @@ +The Miranda system is Copyright (c) Research Software Limited, 1985-2019 +and is distributed under an open source license. For terms see the file +COPYING in the miralib directory. + diff --git a/miralib/manual/34 b/miralib/manual/34 new file mode 100644 index 0000000..4631f32 --- /dev/null +++ b/miralib/manual/34 @@ -0,0 +1,87 @@ +_B_u_g_ _R_e_p_o_r_t_s + +Bug reports should be sent to mira-bugs at the domain + miranda.org.uk +First check below, however, in case it is already known. Also check the +downloads section at miranda.org.uk in case there is a new version of +Miranda in which your bug may be fixed. When sending a bug report, +please state the version number of your Miranda system and the platform +that it is running on. + +The error messages from the Miranda system are mostly self explanatory. +Note, however, that messages of the form "impossible event ..." or +similar indicate that the internal state of the system has become +corrupted. This should be reported as a bug. Segmentation faults also +falls into this category. + +First check if the problem only occurs following a garbage collection. +Garbage collector reports can be turned on by `mira -gc' from the +command line or by /gc within a miranda session. If your error does +appear to be associated with garbage collection you can try running with +a bigger heap and/or getting mira recompiled at a lower level of +optimisation (eg -O instead of -O2, or without -O). Miranda uses a +"conservative collector" which scans the C stack to follow things that +are, or appear to be, pointers into the heap. Unfortunately this is +vulnerable to compiler optimisations affecting the state of the stack. + +Even if the problem does appear to be gc-related it is still worth +reporting. + +The source code, orginally written for 32 bit platforms, has been +extensively revised and tested for 64 bit compatibility. It is quite +possible that some hidden "integer width" problems remain in the code +and will be discovered in use. + +_L_i_s_t_ _o_f_ _k_n_o_w_n_ _b_u_g_s_,_ _d_e_f_i_c_i_e_n_c_i_e_s_,_ _a_n_d_ _u_n_i_m_p_l_e_m_e_n_t_e_d_ _f_e_a_t_u_r_e_s + +If there is not enough heap to compile the current script, mira exits +after reporting this fact. The fix is to increase the heap size: + mira -heap N [filename] +where N is a bigger number than you had before. + +It is not currently permitted to give a type specification for an +identifier defined locally, as part of a _w_h_e_r_e clause. That is (see +formal syntax) `spec' is not allowed after _w_h_e_r_e. + +When abstract objects are tested for equality or order (under <, <= etc) +the result is that obtained by applying the operation to the underlying +representation type. In some cases this will be what you want, but in +others it will be wrong - there ought to be a way of controlling this. + +The standard input cannot be accessed both as a list of characters (with +$-) and as a list of values (with $+) at the same time. If $+ is in +use, an occurrence of $- will evaluate to [], and vice versa. This is +not referentially transparent - uses of $+ and $- ought to share data. + +Scripts with multiple occurrences of $+ also behave opaquely - each +occurrence of $+ reads from the terminal independently, and they do not +share data with each other. (Multiple occurrences of $+ in a single +command-level expression behave transparently, however.) + +There is a subtle issue concerning `show' and %export. If you define a +function which, internally, uses `show' on an object of algebraic type, +and then %export that function to another scope, the format used by the +`show' depends on the status of the algebraic type in the NEW scope. +Thus if the type has been aliased the new constructor names will be +used, and if the algebraic type is no longer in scope, it will show as +"" (this latter case can arise if an abstract type based on +the algebraic type is exported, and one of the signature identifiers +invokes `show' on the base type). Although this behaviour is +defensible, it might be better for each use of `show' at algebraic type +to be frozen to use the constructor names in the scope where it occurs. +[An analogous issue arises with `readvals'.] + +Implementation restrictions not mentioned elsewhere in the manual:- + +A shell command called from mira using `!' is limited to 1024 characters +in length after any implied expansions (eg of `%') have been performed. +The same restriction applies to the result of expanding out a `/e' +command. The pathnames of Miranda scripts are limited to 1024 +characters in length, including the `.m' extension. The name of the +editor supplied for the `/e' command, and the absolute pathnames of the +miralib directory, and of the user's home directory, are also each +limited to 1024 characters in length. + +The name of a Miranda script may not contain spaces (but directory names +with spaces are allowed in pathnames). + diff --git a/miralib/manual/4 b/miralib/manual/4 new file mode 100644 index 0000000..8fa4c83 --- /dev/null +++ b/miralib/manual/4 @@ -0,0 +1,147 @@ +_T_h_e_ _M_i_r_a_n_d_a_ _c_o_m_m_a_n_d_ _i_n_t_e_r_p_r_e_t_e_r + +The Miranda system is invoked from unix by the command + mira [script] +where `script' (optional parameter) is the pathname of a file containing +a set of Miranda definitions. If no script is specified a default name +`script.m' is assumed. The named script (script.m by default) becomes +your _c_u_r_r_e_n_t _s_c_r_i_p_t, during the ensuing Miranda session. You can change +your "current script" during a session, but at any time there is a +unique filename which is current. + +Note that a file containing a Miranda script is expected to have a name +ending in `.m' and the `mira' command will add this extension if +missing. So `mira stuff' will be interpreted as `mira stuff.m'. It is +a convenient and widely used convention that files containing program +sources should have names indicating which language they are written in. + +The set of names in scope at any time are those of the current script, +together with the names of any scripts which it `includes' (see library +directives) plus the names of the _s_t_a_n_d_a_r_d _e_n_v_i_r_o_n_m_e_n_t, which is always +in scope. The current script may be an empty or non-existent file if +you have not yet put any definitions in it. In this case just the names +of the standard environment will be in scope. + +The prompt `Miranda' indicates that you are talking to the Miranda +interpreter. This activity is called a Miranda ``session''. Each +command should be typed on a single line, following the prompt, and is +entered by hitting return. Any command not beginning with one of the +special characters `/', `?', or `!' is assumed to be an expression to be +evaluated. The following commands are available during a session. + +exp + Any Miranda expression typed on a line by itself is evaluated, and the +value is printed on the screen. If the value is of type [char] it is +printed literally, otherwise the special function `_s_h_o_w' is applied to +it to convert it to printable form. Example + Miranda sum[1..100] + 5050 (response) + +There is a special symbol $$ which is always set to the last expression +evaluated. So after the above command $$ will have the value 5050, and +this can be used in the next expression - e.g. `$$/2' will produce the +response 2525 (and the value of `$$' is now 2525). + +exp &> pathname + A background process is set up to evaluate exp, and the resulting +output (including error messages, if any) sent to the designated file. + +exp &>> pathname + As above, except that the output is appended to the designated file, +instead of replacing its previous contents. + +exp :: + Print the type of the expression (instead of the value). Useful for +investigating the type structure of a script. + +? + Lists all identifiers currently in scope, grouped by file of origin, +starting with the standard environment. + +?identifier(s) + Gives more information about any identifier defined in the current +environment (namely its type and the name of the file in which it is +defined). This command will also accept a list of identifiers, +separated by spaces. + +??identifier + Opens the relevant source file at the definition of identifier, which +may be any currently in scope. Try for example ??map + For this and several other features to work Miranda must be configured +to use an appropriate editor - the default is vi, but you can change +this. See section 31 subheading 5 of this manual ("How to change the +default editor"). + +!command + Execute any UNIX shell command. + +!! + Repeat last shell command. + +Note that the character `%' can be used in any Miranda session command, +including a `!' command, as an abbreviation for the pathname of the +current script. So for example + !wc % +does a word count on the current script. (If for some reason you need +to include a literal % character in a command, you can escape it with a +preceding backslash.) + +All the remaining commands begin with `/'. Each of the following +commands can be abbreviated to its first letter. + +/edit (also /e) + Edit the current script. Calls up the currently installed editor +(default _v_i, to change this see remark under ?? above). On quitting the +editor, if changes have been made to any relevant source file, the +Miranda system automatically recompiles the current script and any other +scripts on which it depends and which have been updated. + +/edit pathname (also /e pathname) + Edit arbitrary script. Note that the pathname should end in `.m' and +that this will be added if missing. + +Note by the way that (on most UNIX-like systems) Miranda understands the +commonly used `~' convention in pathnames. That is ~/file means file in +your home directory, and ~jack/file means file in jack's home directory. + +/file (also /f) + Print the name of file containing the current script. + +/file pathname (also /f pathname) + Change to new current script. Equivalent to quitting the Miranda +system and reinvoking it with a new sourcefile. Like /e, /f adds ".m" +to the end of the filename if missing. + +Important special case - reselecting the current script, eg by saying + /f % +forces the current script to be RECOMPILED - this is useful if script +has errors and you wish to see the error messages again. + +/help (also /h) + Display summary of main available commands. There are a few less used +auxiliary commands, not covered here /aux (or /a) will summarise these. + +/man (also /m) + Enter online manual system. + +/quit (also /q) + Quit the Miranda system. Typing the end of file character (control-D) +also has this effect. + +Finally note that $- and $+ are allowed as notations for the standard +input in Miranda expressions. The standard input as a list of +characters is denoted by `$-'. As a simple example, evaluating the +expression + reverse $- +causes everything typed at the keyboard upto the next control-D to be +echoed backwards. + +The notation `$+' also denotes the standard input, but as a sequence of +Miranda expressions (one per line), and returns their values as a list. +For example + sum $+ +reads a sequence of numeric expressions from the standard input, and +returns the sum of their values. See the manual section on reading with +interpretation (under UNIX/Miranda system interface) for further +information. + diff --git a/miralib/manual/5 b/miralib/manual/5 new file mode 120000 index 0000000..a8d227c --- /dev/null +++ b/miralib/manual/5 @@ -0,0 +1 @@ +../helpfile \ No newline at end of file diff --git a/miralib/manual/6 b/miralib/manual/6 new file mode 120000 index 0000000..0ce89f6 --- /dev/null +++ b/miralib/manual/6 @@ -0,0 +1 @@ +../auxfile \ No newline at end of file diff --git a/miralib/manual/7 b/miralib/manual/7 new file mode 100644 index 0000000..bd9e102 --- /dev/null +++ b/miralib/manual/7 @@ -0,0 +1,81 @@ +_E_x_p_r_e_s_s_i_o_n_s + +In Miranda an expression denotes a value. Expressions occur in two +contexts, but have the same(*) syntax in both situations. First, the +basic mode of operation of the Miranda command interpreter is that it +evaluates expressions typed at the terminal (these are called +`command-level expressions'). Second, expressions are an important +syntactic component of _s_c_r_i_p_t_s (because scripts are collections of +definitions, and the right hand sides of definitions are composed of +expressions). + +Expressions typed at the terminal are volatile - only by being made part +of a script can an expression be saved for future use. + +An expression is either simple, or a function application, or an +operator expression, or an operator. + +_A_ _s_i_m_p_l_e_ _e_x_p_r_e_s_s_i_o_n_ _i_s_ _o_n_e_ _o_f_ _t_h_e_ _f_o_l_l_o_w_i_n_g: + +Identifier: (see separate manual entry) these are of two kinds based on +the case of the initial letter + - variable e.g. `x' or `map' + - constructor e.g. `X' or `True' + +Literal, e.g. 136 or "fruit" (see separate manual entry) + +An operator section (see separate manual entry) + +The keyword `_s_h_o_w' or `_r_e_a_d_v_a_l_s' (see separate manual entries) + +A list, such as `[1,5,7,9]' or a `dotdot' list or a list comprehension +(see manual entry on iterative expressions). + +A tuple, such as `(True,"green",37)'. Tuples differ from lists in that +they can have components of mixed type. They are always enclosed in +round parentheses. The empty tuple, which has no components, is written +`()'. Otherwise, a tuple must have at least two components - there is +no concept of a one-tuple. Tuples cannot be subscripted, but their +components can be extracted by pattern matching. Since there is no +concept of a one-tuple, the use of parentheses for grouping does not +conflict with their use for tuple formation. + +Any expression enclosed in parentheses is a simple expression. + +_F_u_n_c_t_i_o_n_ _a_p_p_l_i_c_a_t_i_o_n + is denoted by juxtaposition, and is left associative, so e.g. + f a b + +denotes a curried function application of two arguments. (So f is +really a function of one argument whose result is another function - +thus `f a b' is actually parsed as `(f a) b' - the advantage of this +arrangement is that `f a' has a meaning in its own right, it is a +partially applied version of f.) + +_O_p_e_r_a_t_o_r_ _e_x_p_r_e_s_s_i_o_n_s + e.g. `5*x-17' +There are a variety of infix and prefix operators, of various binding +powers (see manual entry on operators). Note that function application +is more binding than any operator. + +An operator on its own can be used as the name of the corresponding +function, as shown in the following examples + arith2_ops = [+,-,*,/,div,mod,^] + sum = foldr (+) 0 + +both of which are legal definitions. Note that when an operator is +passed as a parameter it needs to be parenthesised, to force the correct +parse. An ambiguity arises in the case of `-' which has two meanings as +an operator (infix and prefix) - the convention is that `-' occurring +alone always refers to the infix (i.e. dyadic) case. The name `neg' is +provided for the unary minus function, as part of the standard +environment. + +A formal syntax for expressions can be found in the manual section +called `Formal syntax of Miranda scripts'. + +(*) _N_o_t_e There is one exception to the rule that command level +expressions have the same syntax as expressions inside scripts - the +notation `$$', meaning the last expression evaluated, is allowed only in +command level expressions. + diff --git a/miralib/manual/8 b/miralib/manual/8 new file mode 100644 index 0000000..8909b5c --- /dev/null +++ b/miralib/manual/8 @@ -0,0 +1,75 @@ +_O_p_e_r_a_t_o_r_s_ _a_n_d_ _t_h_e_i_r_ _b_i_n_d_i_n_g_ _p_o_w_e_r_s + +Here is a list of all prefix and infix operators, in order of increasing +binding power. Operators given on the same line are of the same binding +power. Prefix operators are identified as such in the comments - all +others are infix. + + operator comments + + : ++ -- right associative + \/ associative + & associative + ~ prefix + > >= = ~= <= < continued relations allowed, eg 0[*]->[*] +++ -- list concatenation, list subtraction, both of type [*]->[*]->[*] + A formal definition of list subtraction is given below. +\/ & logical `or', `and', both of type bool->bool->bool +~ logical negation, type bool->bool +> >= = ~= <= < + comparison operators, all of type *->*->bool + Note that there is an ordering defined on every (non-function) + type. In the case of numbers, characters and strings the order + is as you would expect, on other types it as an arbitrary but + reproducible ordering. Equality on structured data is a test + for isomorphism. (i.e. in LISP terms it is "EQUAL" not "EQ"). + It is an error to test functions for equality or order. ++ - plus, minus, type num->num->num +- unary minus, type num->num + Note that in Miranda unary minus binds less tightly than + the multiplication and division operators. This is the + usual algebraic convention, but is different from PASCAL. +* / _d_i_v _m_o_d + times, divide, integer divide, integer remainder, + all of type num->num->num + `/' can be applied to integers or fractional numbers, and + always gives a fractional result, so eg 6/2 is 3.0 + _d_i_v and _m_o_d can only be applied to integers and + give integer results, eg 7 div 2 is 3, 7 mod 2 is 1. + _d_i_v and _m_o_d obey the following laws, for a b any integers + with b ~= 0 + (i) b * (a _d_i_v b) + a _m_o_d b = a + (ii) if b>0 then 0 <= a _m_o_d b < b + if b<0 then b < a _m_o_d b <= 0 +^ `to the power of', type num->num->num +. function composition, type (**->***)->(*->**)->*->*** +# length of list, type [*]->num +! list subscripting, type [*]->num->* + note that the first element of a non-empty list x is x!0 and the + last element is x!(#x-1) +$identifier $IDENTIFIER + do-it-yourself infix, `a $f b' is equivalent in all contexts to + `f a b'. Also works for constructors of two or more arguments. + +_N_o_t_e_ _o_n_ _l_i_s_t_ _s_u_b_t_r_a_c_t_i_o_n + Here is a formal definition of the `--' operator in Miranda. It is +defined using an auxiliary function `remove' which removes the first +occurrence (if any) of a given item from a list. + + x -- [] = x + x -- (b:y) = (remove b x) -- y + remove b [] = [] + remove b (a:x) = x, if a=b + = a:remove b x, otherwise + diff --git a/miralib/manual/9 b/miralib/manual/9 new file mode 100644 index 0000000..3d7599a --- /dev/null +++ b/miralib/manual/9 @@ -0,0 +1,62 @@ +_S_e_c_t_i_o_n_s + +An infix operator can be partially applied, by supplying it with only +one of its operands, the result being a function of one argument. Such +expressions are always parenthesised, to avoid ambiguity, and are called +`sections'. Two different kinds of sections (called presections and +postsections) are possible since either the first or the second operand +can be supplied. + +An example of a presection is + (1/) +which denotes the reciprocal function. An example of a postsection is + (/3) +which gives a concise notation for the `divide by three' function. Note +that both of these examples are functions of type (num->num). With one +exception (see below) sections can be formed using any infix operator. +Further examples are (0:) which is a function for prefixing lists of +numbers with zero, and (^2) which is the square function. + +Sections may be regarded as the analogue of currying for infix +operators. They are a minor syntactic convenience, and do not really +add any power to the language, since any function denoted in this way +could have been introduced by explicit definition. For the first two +examples given above we could have written, say + reciprocal y = 1/y + divide_by_three x = x/3 +and then used the function names, although this would have been somewhat +more verbose. + +To summarise the conventions for infixes, taking infix division as an +example, note that the following expressions are all equivalent. + a / b + (/) a b + (a /) b + (/ b) a + +The usual rules about operator precedence (see manual section on +operators) apply to sections. For example we can write (a*b+) but not +(a+b*), because `*' is more binding than `+'. The latter example should +have been written ((a+b)*). As always when writing complicated +expressions, if there is any possibility of ambiguity it is better to +put in extra parentheses. + +_S_p_e_c_i_a_l_ _c_a_s_e + It is not possible to form a postsection in infix minus, because of a +conflict of meaning with unary minus. For example: + (-b) +is a parenthesised occurrence of negative b, not a section. As a way +round this there is a function `subtract' in the standard environment +with the definition:- subtract x y = y - x. This is a normal curried +function, so we can write (subtract b) to get the function that +subtracts b from things. + +Presections in infix minus, such as (a-), cause no ambiguity. There are +no problems with infix plus because Miranda does not have a unary plus +operator. + +_A_c_k_n_o_w_l_e_d_g_e_m_e_n_t: + The idea of sections is due to Richard Bird (of Oxford University +Programming Research Group) and David Wile (of USC Information Sciences +Institute). + diff --git a/miralib/manual/99 b/miralib/manual/99 new file mode 100755 index 0000000..1a8feb8 --- /dev/null +++ b/miralib/manual/99 @@ -0,0 +1,5 @@ +#! /bin/sh +echo a listing of the manual is being put in the file +echo "mira.man" in your home directory ... +echo +./printman > $HOME/mira.man diff --git a/miralib/manual/contents b/miralib/manual/contents new file mode 100644 index 0000000..42cbf25 --- /dev/null +++ b/miralib/manual/contents @@ -0,0 +1,22 @@ +_M_i_r_a_n_d_a_ _S_y_s_t_e_m_ _M_a_n_u_a_l _ _C_o_p_y_r_i_g_h_t_ _R_e_s_e_a_r_c_h_ _S_o_f_t_w_a_r_e_ _L_i_m_i_t_e_d_ _1_9_8_5_-_2_0_2_0 + + 1. How to use the manual system 20. Algebraic types + 2. About the name "Miranda" 21. Abstract types + 3. About this release 22. Empty types + 4. The Miranda command interpreter 23. The special function _s_h_o_w + 5. Brief summary of main commands 24. Formal syntax of Miranda scripts + 6. List of remaining commands 25. Comments on syntax + 7. Expressions 26. Miranda lexical syntax + 8. Operators 27. The library mechanism + 9. Operator sections 28. The standard environment +10. Identifiers 29. Literate scripts +11. Literals 30. Some hints on Miranda style +12. Tokenisation and layout 31. UNIX/Miranda system interface +13. Iterative expressions 32. -->> CHANGES <<-- +14. Scripts, overview 33. Copying +15. Definitions 34. Bug reports +16. Pattern matching +17. Compiler directives +18. Basic type structure 99. Create a printout of the manual +19. Type synonyms 100. An Overview of Miranda (paper) + diff --git a/miralib/manual/howtoprint b/miralib/manual/howtoprint new file mode 100644 index 0000000..c5e540c --- /dev/null +++ b/miralib/manual/howtoprint @@ -0,0 +1,4 @@ +To get a hard copy, say the following + lpr mira.man +or similar, as a UNIX command, from your home directory. + diff --git a/miralib/manual/permission b/miralib/manual/permission new file mode 100644 index 0000000..271052b --- /dev/null +++ b/miralib/manual/permission @@ -0,0 +1,6 @@ +/----------------------------------------------------------------------\ +| The Miranda System Manual is Copyright (c) Research Software | +| Limited, 1985-2019. It may be freely reproduced, with or without | +| changes, for use with the Miranda System but commercial publication | +| rights are reserved to the Copyright holder. | +\----------------------------------------------------------------------/ diff --git a/miralib/manual/printman b/miralib/manual/printman new file mode 100755 index 0000000..6786e7c --- /dev/null +++ b/miralib/manual/printman @@ -0,0 +1,42 @@ +#! /bin/sh +if test -f contents +then cat contents +else echo printman: no contents; exit +fi +if test -f ../.version +then read VERSION < ../.version +else VERSION=?? +fi +echo "printout of online manual pages for version $VERSION" +cat .epoch +echo +cat permission +echo +for i in ? ?? +do test "$i" = "99" && exit + echo :::::::::::::::::::::: + echo $i + echo :::::::::::::::::::::: + if test -d $i + then if test -f $i/contents + then cat $i/contents + else echo $i: no contents; break + fi + for j in $i/? + do echo :::::::::::::::::::::: + if test -d $j + then echo $j omitted #don't go into 3rd level + echo :::::::::::::::::::::: + else echo $j + echo :::::::::::::::::::::: + cat $j + fi + done + else cat $i + fi +done +echo :::::::::::::::::::::: +echo APPENDIX +echo :::::::::::::::::::::: +echo +cat 100 diff --git a/miralib/menudriver.csh b/miralib/menudriver.csh new file mode 100755 index 0000000..2aa89e7 --- /dev/null +++ b/miralib/menudriver.csh @@ -0,0 +1,104 @@ +#!/bin/csh -f +# menu driver - Copyright Research Software Ltd 1985, 2006 +# this version modified to ignore execute permissions of files + +# see below for explanation of these variables, which we +# set to defaults if not present in the user's environment + +if(! $?MENUVIEWER) set MENUVIEWER = cat #ALTERNATIVE: more +if(! $?VIEWER) then +# choose one of these by removing the '#' in column one + set VIEWER = 'less -EX' RETURNTOMENU = NO +# set VIEWER = less RETURNTOMENU = YES +# set VIEWER = 'more -d' RETURNTOMENU = NO +endif + +set sansnl n invalid last oldlasts noglob +set histchars = '@^' #neutralize '!' + +if("`echo -n`" == '') then #use flag -n to suppress newline, if working +set sansnl = '-n' +endif + +if("$1" != '') cd "$1" +set top = "`pwd`" +while( -f contents ) + if("$n" == '') then + clear + if("$invalid" != '') echo invalid option "$invalid" + set invalid = '' + $MENUVIEWER contents; + echo $sansnl ::please type selection number \(or q to quit\): + set line = "$<" + set n = `expr " $line" : ' *\([^ ]*\)'` + endif + if("$n" == '.' && "$last" != '') then + set n = $last; + else if("$n" == '+' && "$last" != '' && "$last" != '.') then + set n = `expr $last + 1` + else if("$n" == '-' && "$last" != '' && "$last" != '.') then + set n = `expr $last - 1` + endif + if("$n" != '') then + if(-d "$n") then + if(-f "$n/contents") then + cd "$n"; set oldlasts = "$n,$oldlasts" last = "." + else set invalid = "$n" + endif + set n = '' + else if(-f "$n") then + if("$n" == '99') then #special case, 99 is an executable + clear; "./$n" + else clear; + $VIEWER "$n" + if("$RETURNTOMENU" == 'YES') then + set last = $n n = '' + continue #next iteration of while-loop + endif + endif + echo $sansnl ::next selection \(return to go back to menu, q to quit\): + set last = $n line = "$<" + set n = `expr " $line" : ' *\([^ ]*\)'` + else if("$n" == 'q' || "$n" == '/q') then + exit + else if("$n" == '???') then # ??? interrogates display settings + echo " MENUVIEWER='$MENUVIEWER'" + echo " VIEWER='$VIEWER', RETURNTOMENU='$RETURNTOMENU'" + echo these can be changed by setting environment variables \ +of the same names + set n = '' + echo $sansnl '[Hit return to continue]' + set lose = "$<" + else if( "$n" =~ !* ) then + set line = `expr "$line" : ' *\(.*\)'` + set line = `expr "$line" : '\(.*[^ ]\) *'` + if( ".$line" == '.!!' || ".$line" == '.!' ) then + if(! $?lastbang) then + set invalid = "$n" n = ''; continue + else echo !"$lastbang" + endif + else set lastbang = `expr "$line" : '!\(.*\)'` + endif + $lastbang + echo $sansnl '[Hit return to continue]' + set n = '' + set lose = "$<" + else set invalid = "$n" n = '' + endif + else if("$oldlasts" == '') exit #we are at the root of the tree + cd .. + set last = `expr $oldlasts : '\([^,]*\)'` + set oldlasts = `expr $oldlasts : '[^,]*,\(.*\)'` + endif +end #of while-loop +exit +# Explanation of variables +# +# MENUVIEWER is the program used to display contents pages +# +# VIEWER is the program used to display individual sections +# +# RETURNTOMENU=YES prevents another prompt being given after displaying +# each section, causing instead an immediate return to contents page. It +# should be `YES' if VIEWER is a program that pauses for input at end of +# file, `NO' if VIEWER is a program that quits silently at end of file. diff --git a/miralib/menudriver.sh b/miralib/menudriver.sh new file mode 100755 index 0000000..81d4362 --- /dev/null +++ b/miralib/menudriver.sh @@ -0,0 +1,102 @@ +#! /bin/sh +# menu driver - Copyright Research Software Ltd 1985, 2006 +# this version modified to ignore execute permissions of files + +# see below for explanation of these variables, which we +# set to defaults if not present in the user's environment + +test "$MENUVIEWER" || MENUVIEWER=cat #ALTERNATIVE: more +if test ! "$VIEWER" +then +# choose one of these by removing the '#' in column one + VIEWER='less -EX'; RETURNTOMENU=NO +# VIEWER=less, RETURNTOMENU=YES +# VIEWER='more -d'; RETURNTOMENU=NO +fi + +if test -z "`echo -n`" #use flag -n to suppress newline, if working +then sansnl='-n' +fi + +cd "$1" +top="`pwd`" +while test -f contents +do + if test '' = "$n" + then echo  #clear + test ."$invalid" = . || echo invalid option "$invalid" + invalid="" + $MENUVIEWER contents; + echo $sansnl ::please type selection number \(or q to quit\): + read n + fi + if test '.' = "$n" -a "$last" + then n=$last + elif test '+' = "$n" -a "$last" -a "$last" != . + then n=`expr $last + 1` + elif test '-' = "$n" -a "$last" -a "$last" != . + then n=`expr $last - 1` + fi + if test '' != "$n" + then if test -d "$n" + then if test -f "$n/contents" + then cd "$n"; oldlasts=$n:$oldlasts; last="."; + else invalid="$n"; fi + n="" + elif test -f "$n" + then if test '99' = "$n" #special case, 99 is an executable + then echo ; "./$n" + else echo  #clear + $VIEWER "$n" + if test "$RETURNTOMENU" = YES + then last=$n; n=""; continue #next iteration of while-loop + fi + fi + echo $sansnl ::next selection \(return to go back to menu, q to quit\): + last=$n; read n + elif test ."$n" = .q -o ."$n" = ./q + then exit + elif test '???' = "$n" # ??? interrogates display settings + then echo " MENUVIEWER='$MENUVIEWER'" + echo " VIEWER='$VIEWER', RETURNTOMENU='$RETURNTOMENU'" + echo these can be changed by setting environment variables \ +of the same names + n="" + echo $sansnl '[Hit return to continue]' + read lose + else case $n in + !*) if test ".$n" = '.!!' -o ".$n" = '.!' + then if test "$lastbang" = '' + then invalid="$n"; n=""; continue + else echo !"$lastbang" + fi + else lastbang=`expr "$n" : '!\(.*\)'` + fi + $lastbang + echo $sansnl '[Hit return to continue]' + n="" + read lose ;; + *) invalid="$n"; n="" ;; + esac + fi + else test "$oldlasts" || exit #we are at the root of the tree + cd .. + last=`expr $oldlasts : '\([^:]*\)'` + oldlasts=`expr $oldlasts : '[^:]*:\(.*\)'` + fi +done +exit +# Oct 2003 modified for Peter Bartke to overcome problem on UWIN +# no test -x, instead all files displayed except 99 which is executed +# May 2006 use echo $sansnl because echo -n not portable + +# Explanation of variables +# +# MENUVIEWER is the program used to display contents pages +# +# VIEWER is the program used to display individual sections +# +# RETURNTOMENU=YES prevents another prompt being given after displaying +# each section, causing instead an immediate return to contents page. It +# should be `YES' if VIEWER is a program that pauses for input at end of +# file, `NO' if VIEWER is a program that quits silently at end of file. diff --git a/miralib/prelude b/miralib/prelude new file mode 100644 index 0000000..f9fe7a7 --- /dev/null +++ b/miralib/prelude @@ -0,0 +1,110 @@ +||names defined in this file are not in scope for users - they are part +||of the internal mechanisms of the Miranda system. + +||the following three identifiers are "untypeable" and defined internally +||changetype::*->** ||primitive function, semantically equivalent to id +||first::*->** ||gets first element of a tuple +||rest::*->** ||gets rest of a tuple (i.e. without first component) + +||offside::[char] ||defined internally and used by indent, see below + + diagonalise :: [[*]]->[*] ||used by [//] comprehensions + diagonalise x = diag 1 x ||when nested does "cantorian" diagonalisation + diag n [] = [] + diag n x = map hd px++diag (#px+1)rest, otherwise + where + px = filter (~=[]) (take n x) + rest = map tl px ++ drop n x + listdiff::[*]->[*]->[*] ||listdiff defines the action of "--" + listdiff x [] = x + listdiff x (b:y) = listdiff (remove b x) y + remove b [] = [] + remove b (a:x) = x, if a=b + = a:remove b x, otherwise + showbool::bool->[char] + showbool True = "True" + showbool False = "False" +||shownum defined internally + base r x = "0", if x=0 ||base is used by charname + = f x, otherwise + where + f 0 = [] + f n = f(n div r) ++ [mkdigit(n mod r)] + mkdigit n = decode(n + code '0'), if n<10 + = decode(n - 10 + code 'a'), if 10<=n<36 + showchar::char->[char] + showchar x = "'" ++ charname x ++ "'" +||note - charname has the right conventions for showchar +||i.e. ' is escaped and " is not escaped - showstring inverts this + charname '\\' = "\\\\" + charname '\'' = "\\\'" + charname x = [x], if 32 <= code x < 127 \/ 160 <= code x < 256 + charname '\a' = "\\a" + charname '\b' = "\\b" + charname '\f' = "\\f" + charname '\n' = "\\n" + charname '\r' = "\\r" + charname '\t' = "\\t" + charname '\v' = "\\v" + charname x = "\\" ++ pad 3 (base 10 n), if n<1000 ||H=this case only & no pad + = "\\x" ++ pad 4 (base 16 n), if n<=0xffff + = "\\X" ++ pad 6 (base 16 n), otherwise + where + n = code x + pad w s = rep(w-#s)'0'++s + rep n x = [], if n<=0 + = x:rep (n-1) x, otherwise + showlist::(*->[char])->[*]->[char] + showlist f x = '[':rest + where + rest = "]", if x=[] + = f(hd x)++foldr g "]" (tl x), otherwise + g a s = ',':f a++s + showstring::[char]->[char] + showstring x = '"' : showstr x + showstr [] = "\"" + showstr ('"':x) = "\\\"" ++ showstr x + showstr (a:x) = s ++ showstr x ||for Haskell style padding use s1 here + where ||see also line marked H above + s = charname a +|| s1 = s ++ "\\&", if clash s x +|| = s, otherwise +|| clash ('\\':c:cs) (d:ds) = digit c & digit d +|| clash s x = False + digit c = '0' <= c <= '9' + shownum1::num->[char] + shownum1 n = "("++shownum n++")", if n<0 + = shownum n, otherwise + showparen::(*->[char])->*->[char] + showparen f x = "("++f x++")" + showpair::(*->[char])->(**->[char])->***->[char] + showpair f1 f2 tup = f1(first tup)++","++f2(rest tup) + showvoid::()->[char] + showvoid () = "()" + showfunction::(*->**)->[char] + showfunction x = "" + showabstract::*->[char] + showabstract x = "" + showwhat::*->[char] + showwhat x = error "undeclared show-function", if x=x +||the following function is used to implement the offside rule (under %bnf) + indent :: *->**->** || * is type of `col' function, ** is parser + outdent :: *->* || * is a parser + indent = changetype indent1 + outdent = changetype outdent1 + indent1 col f ((a,s):x) + = f ((a,s):cutoff col (col s) x), if a~=offside + indent1 col f x = f x + cutoff col n = g + where + g ((a,s):x) = (a,s):g x, if col s>=n + = (offside,s):(a,s):x, otherwise + g [] = [] + outdent1 f = reconstruct.f + reconstruct (m:x) = m:g x + where + g ((a,s):x) = x, if a=offside + g (t:x) = t:g x + g [] = [] + reconstruct fail = fail ||internal repn of failure is a non-CONS object +||offside is defined internally and differs from every string diff --git a/miralib/stdenv.m b/miralib/stdenv.m new file mode 100644 index 0000000..8c53ac8 --- /dev/null +++ b/miralib/stdenv.m @@ -0,0 +1,761 @@ +> ||The Miranda Standard Environment (C) Research Software Limited 1989 + +We give here, in alphabetical order, a brief explanation of all the +identifiers in the Miranda standard environment, each followed by its +definition (except in a few cases where the definition cannot +conveniently be given in Miranda). The lines marked with a `>' in +column one are formal program text, the other lines in the file are +comment. Note that a number of the functions given here are defined +internally (for speed) even though their definitions could have been +given in Miranda - in these cases the Miranda definition is given as a +comment. This is the standard environment of Miranda release two. + +Added October 2019 - showhex, showoct - see below. + +`abs' takes the absolute value of a number - e.g. abs (-3) is 3, abs 3.5 +is 3.5 + +> abs :: num->num +> abs x = -x, if x<0 +> = x, otherwise + +`and' applied to a list of truthvalues, takes their logical conjunction. + +> and :: [bool]->bool +> and = foldr (&) True + +`arctan' is the trigonometric function, inverse tangent. It returns a +result in the range -pi/2 to pi/2. See also `sin', `cos'. + +> arctan :: num->num ||defined internally + +`bool' is the type comprising the two truthvalues. + + bool ::= False | True ||primitive to Miranda + +`char' is the type comprising the Latin-1 character set (e.g. 'a', +'\n'). + + char :: type ||primitive to Miranda + +`cjustify' applied to a number and a string, centre justifies the string +in a field of the specified width. See also `ljustify', `rjustify', +`spaces'. + +> cjustify :: num->[char]->[char] +> cjustify n s = spaces lmargin++s++spaces rmargin +> where +> margin = n - # s +> lmargin = margin div 2 +> rmargin = margin - lmargin + +`code' applied to a character returns its code number. Example + code 'a' = 97. +See also `decode'. + +> code :: char->num ||defined internally + +`concat' applied to a list of lists, joins them all together into a +single list with `++'. E.g. + concat [[1,2],[],[3,4]] = [1,2,3,4]. + +> concat :: [[*]]->[*] +> concat = foldr (++) [] + +`const' is a combinator for creating constant-valued functions. E.g. +(const 3) is the function that always returns 3. + +> const :: *->**->* +> const x y = x + +`converse' is a combinator for inverting the order of arguments of a +two-argument function. + +> converse :: (*->**->***)->**->*->*** +> converse f a b = f b a + +`cos' is the trigonometric cosine function, argument in radians. + +> cos :: num->num ||defined internally + +`decode' applied to an integer returns the character with that code. + +> decode :: num->char ||defined internally + +`digit' is a predicate on characters. True if the character is a digit. +See also `letter'. + +> digit :: char->bool +> digit x = '0'<=x<='9' + +`drop' applied to a number and a list returns the list with that many +elements removed from the front. If the list has less than the required +number of elements, `drop' returns []. Example + drop 2 [1,2,3,4] = [3,4] +See also `take'. + +> drop :: num->[*]->[*] ||defined internally, as below + + drop (n+1) (a:x) = drop n x + drop n x = x, if integer n + = error "drop applied to fractional number", otherwise + +`dropwhile' applied to a predicate and a list, removes elements from the +front of the list while the predicate is satisfied. Example: + dropwhile digit "123gone" = "gone" +See also `takewhile'. + +> dropwhile :: (*->bool)->[*]->[*] +> dropwhile f [] = [] +> dropwhile f (a:x) = dropwhile f x, if f a +> = a:x, otherwise + +`e' is a transcendental number, the base of natural logarithms. + +> e :: num +> e = exp 1 + +`entier' when applied to a number returns its integer part, meaning the +largest integer not exceeding it. E.g. + entier 1.0 = 1 + entier 3.5 = 3 + entier (-3.5) = -4. +Notice that for Miranda the number `1' and the number `1.0' are +different values - for example they yield different results under the +`integer' test. However `1=1.0' is True, because of the automatic +conversion from integer to float. + +> entier :: num->num ||defined internally + +A useful fact about `entier', which relates it to the operators div and +mod, is that the following law holds for any integers a, b with b~=0 and +a/b within the range for which integers can be represented exactly as +fractional numbers + a div b = entier (a/b) + +`error' applied to a string creates an error value with the associated +message. Error values are all equivalent to the undefined value - any +attempt to access the value causes the program to terminate and print +the string as a diagnostic. + +> error :: [char]->* ||defined internally + +`exp' is the exponential function on real numbers. See also `log'. + +> exp :: num->num ||defined internally + +`filemode' applied to a string representing the pathname of a UNIX file, +returns a string of length four giving the access permissions of the +current process to the file. The permissions are encoded as (in this +order) "drwx", any permission not granted is replaced by a '-' +character. If there is no file at pathname p, filemode p returns the +empty string. Example + member (filemode f) 'w' +tests f for write permission. See also `getenv', `read', `system'. + +> filemode :: [char]->[char] ||defined internally + +`filestat' applied to a UNIX pathname returns three integers +((inode,device),mtime), where mtime is the time-last-modified of the +file, in seconds since 00.00h on 1 Jan 1970. The pair (inode,device) +identifies a file uniquely, regardless of the pathname used to reach it. +A non-existent file has inode & device (0,-1) and mtime 0. + +> filestat :: [char]->((num,num),num) ||defined internally + +`filter' applied to a predicate and a list, returns a list containing +only those elements that satisfy the predicate. Example + filter (>5) [3,7,2,8,1,17] = [7,8,17] + +> filter :: (*->bool)->[*]->[*] +> filter f x = [a | a<-x; f a] + +`foldl' folds up a list, using a given binary operator and a given start +value, in a left associative way. Example: + foldl op r [a,b,c] = (((r $op a) $op b) $op c) +But note that in order to run in constant space, foldl forces `op' to +evaluate its first parameter. See the definitions of `product', +`reverse', `sum' for examples of its use. See also `foldr'. + +> foldl :: (*->**->*)->*->[**]->* ||defined internally, as below + + foldl op r [] = r + foldl op r (a:x) = strict (foldl op) (op r a) x + where + strict f x = seq x (f x) + +WARNING - this definition of foldl differs from that in older versions +of Miranda. The one here is the same as that in Bird and Wadler (1988). +The old definition had the two args of `op' reversed. That is:- + old_foldl op r = new_foldl (converse op) r +the function `converse' has been added to the standard environment. + +`foldl1' folds left over non-empty lists. See the definitions of `max', +`min' for examples of its use. + +> foldl1 :: (*->*->*)->[*]->* ||defined internally, as below + + foldl1 op (a:x) = foldl op a x + foldl1 op [] = error "foldl1 applied to []" + +`foldr' folds up a list, using a given binary operator and a given start +value, in a right associative way. Example: + foldr op r [a,b,c] = a $op (b $op (c $op r)) +See the definitions of `and', `concat', `or', for examples of its use. + +> foldr :: (*->**->**)->**->[*]->** ||defined internally, as below + + foldr op r [] = r + foldr op r (a:x) = op a (foldr op r x) + +`foldr1' folds right over non-empty lists. + +> foldr1 :: (*->*->*)->[*]->* +> foldr1 op [a] = a +> foldr1 op (a:b:x) = op a (foldr1 op (b:x)) +> foldr1 op [] = error "foldr1 applied to []" + +`force' applied to any data structure, returns it, but forces a check +that every part of the structure is defined. Example + hd(force x) +returns the hd of x, but fully evaluates x first (so x must be finite). +See also `seq'. Notice in particular the idiom `seq (force a) b' which +returns `b' but only after fully evaluating `a'. + +> force :: *->* ||defined internally + +`fst' returns the first component of a pair. See also `snd'. + +> fst :: (*,**)->* +> fst (a,b) = a + +`getenv' looks up a string in the user's UNIX environment. Example + getenv "HOME" +returns the pathname of your home directory. [If you want to see what +else is in your UNIX environment, say `printenv' as a UNIX command.] + +> getenv :: [char]->[char] ||defined internally + +`hd' applied to a non empty list, returns its first element. It is an +error to apply `hd' to the empty list, []. See also `tl'. + +> hd :: [*]->* +> hd (a:x) = a +> hd [] = error "hd []" + +`hugenum' is the largest fractional number that can exist in this +implementation (should be around 1e308 for IEEE standard 64 bit floating +point). See also `tinynum'. + +> hugenum :: num ||defined internally + +`id' is the identity function - applied to any object it returns it. + +> id :: *->* +> id x = x + +`index' applied to a (finite or infinite) list, returns a list of its +legal subscript values, in ascending order. E.g. index "hippopotamus" +is [0,1,2,3,4,5,6,7,8,9,10,11]. + +> index :: [*]->[num] +> index x = f 0 x +> where +> f n [] = [] +> f n (a:x) = n:f(n+1)x + +`init' is dual to `tl', it returns a list without its last component. +Example + init [1,2,3,4] = [1,2,3]. +See also `last'. [Note, by the `dual' of a list processing function we +mean the function which does the same job in a world where all lists +have been reversed.] + +> init :: [*]->[*] +> init (a:x) = [], if x=[] +> = a:init x, otherwise +> init [] = error "init []" + +`integer' is a predicate on numbers. True if and only if the number is +not fractional. + +> integer :: num->bool ||defined internally + +`iterate' - iterate f x returns the infinite list [x, f x, f(f x), ... ] +Example: iterate (2*) 1 yields a list of the powers of 2. + +> iterate :: (*->*)->*->[*] +> iterate f x = [y | y<-x, f y ..] + +Note use of ", .." to generate an arbitrary sequence (see manual section +13/2). + +`last' applied to a non empty list returns its last element. This +function is the dual of `hd'. Note that for any non-empty list x + (init x ++ [last x]) = x + +> last :: [*]->* ||defined internally, as below + + last x = x!(#x-1) + +`lay' applied to a list of strings, joins them together after appending +a newline character to each string. Example + lay ["hello","world"] = "hello\nworld\n" +Used to format output thus, + lay(map show x) +as a top level expression, causes the elements of the list x to be +printed one per line. See also `layn', `lines'. + +> lay :: [[char]]->[char] +> lay [] = [] +> lay (a:x) = a++"\n"++lay x + +`layn' is similar to `lay', but produces output with numbered lines. + +> layn :: [[char]]->[char] +> layn x = f 1 x +> where +> f n [] = [] +> f n (a:x) = rjustify 4 (show n) ++") "++a++"\n"++f (n+1) x + +'letter' is a predicate on characters. True if the character is a +letter. + +> letter :: char->bool +> letter c = 'a'<=c<='z' \/ 'A'<=c<='Z' + +`limit' applied to a list of values, returns the first value which is +the same as its successor. Useful in testing for convergence. For +example the following Miranda expression computes the square root of 2 +by the Newton-Raphson method + limit [x | x<-2, 0.5*(x + 2/x).. ] + +> limit :: [*]->* +> limit (a:b:x) = a, if a=b +> = limit (b:x), otherwise +> limit other = error "incorrect use of limit" + +`lines' applied to a list of characters containing newlines, returns a +list of lists, by breaking the original into lines. The newline +characters are removed from the result. Example, `lines' applied to + "hello world\nit's me,\neric\n" +returns ["hello world","it's me","eric"]. Note that `lines' treats +newline as a terminator, not a separator (although it will tolerate a +missing '\n' on the last line). + +> lines :: [char]->[[char]] +> lines [] = [] +> lines (a:x) = []:lines x, if a='\n' +> = (a:x1):xrest, otherwise +> where +> (x1:xrest) = lines x, if x~=[] +> = []:[], otherwise +> ||this handles missing '\n' on last line + +Note that the inverse of `lines' is the function `lay', in that applying +`lay' to the output of `lines' will restore the original string (except +that a final newline will be added, if missing in the original string). + +`ljustify' applied to a number and a string, left justifies the string +in a field of the specified width. + +> ljustify :: num->[char]->[char] +> ljustify n s = s++spaces(n - # s) + +`log' applied to a number returns its natural logarithm (i.e. logarithm +to the base `e'). It is the inverse of the exponential function, `exp'. +See also log10. Note that the log functions use a different algorithm +when applied to integer arguments (rather than just converting to float +first) so it is possible to take log, or log10, of very large integers. + +> log :: num->num ||defined internally + +`log10' applied to a number returns its logarithm to the base 10. + +> log10 :: num->num ||defined internally + +`map' applied to a function and a list returns a copy of the list in +which the given function has been applied to every element. + +> map :: (*->**)->[*]->[**] +> map f x = [f a | a<-x] + +`map2' is similar to `map', but takes a function of two arguments, and +maps it along two argument lists. We could also define `map3', `map4' +etc., but they are much less often needed. + +> map2 :: (*->**->***)->[*]->[**]->[***] +> map2 f x y = [f a b | (a,b)<-zip2 x y] + +Note: the Bird and Wadler function `zipwith' is just an uncurried +version of `map2', that is `zipwith f (x,y)' means `map2 f x y'. + +`max' applied to a list returns the largest element under the built in +ordering of `>'. Examples + max [1,2,12,-6,5] = 12 + max "hippopotamus" = 'u' +See also `min', `sort'. + +> max :: [*]->* +> max = foldl1 max2 + +`max2' applied to two values of the same type returns the larger under +the built in ordering of '>'. See also `min2'. + +> max2 :: *->*->* +> max2 a b = a, if a>=b +> = b, otherwise + +`member' applied to a list and a value returns True or False as the +value is or not present in the list. + +> member :: [*]->*->bool +> member x a = or (map (=a) x) + +`merge' applied to two sorted lists merges them to produce a single +sorted result. Used to define `sort', see later. + +> merge :: [*]->[*]->[*] ||defined internally, as below + + merge [] y = y + merge (a:x) [] = a:x + merge (a:x) (b:y) = a:merge x (b:y), if a<=b + = b:merge (a:x) y, otherwise + +`min' applied to a list returns its least member under `<'. + +> min :: [*]->* +> min = foldl1 min2 + +`min2' applied to two values of the same type returns the smaller under +the built in ordering of '<'. + +> min2 :: *->*->* +> min2 a b = b, if a>b +> = a, otherwise + +`mkset' applied to a list returns a copy of the list from which any +duplicated elements have been removed. A list without duplications can +be used to represent a set, whence the name. Works even on infinite +list, but (beware) takes a time quadratic in the number of elements +processed. + +> mkset :: [*]->[*] +> mkset [] = [] +> mkset (a:x) = a:filter (~=a) (mkset x) + +`neg' is a function of one numeric argument, with the same action as the +unary `-' operator. + +> neg :: num->num +> neg x = -x + +`num' is the type comprising both integer and fractional numbers (such +as 42, -12.73e8). + + num :: type ||primitive to Miranda + +`numval' converts a numeric string to the corresponding number - accepts +optional leading "-" followed by integer or floating point number, using +same rules as the Miranda compiler. Strings containing inappropriate +characters cause an error (exception - leading white space is harmless). + +> numval :: [char]->num ||defined internally + +`or' applied to a list of truthvalues, takes their logical disjunction. + +> or :: [bool]->bool +> or = foldr (\/) False + +`pi' is the well known real number (the ratio of the circumference of a +circle to its diameter). + +> pi :: num +> pi = 4*arctan 1 + +`postfix' takes an element and a list and adds the element to the end of +the list. This is the dual of the prefix operator, `:'. + +> postfix :: *->[*]->[*] +> postfix a x = x ++ [a] + +`product' applied to list of numbers returns their product. See also +`sum'. + +> product :: [num]->num +> product = foldl (*) 1 + +`read' returns the contents of file with a given pathname. Provides an +interface to the UNIX filing system. If the file is empty `read' +returns [], but if the file does not exist, or lacks read permission, +`read' causes an error. See also `filemode', `getenv'. + +> read :: [char]->[char] ||defined internally + +`readb' reads a file as bytes - useful in a UTF-8 locale, where binary +data may contain illegal characters if read as text. (In a non UTF-8 +locale the results of read and readb do not differ.) See manual section +31/9 for more information. + +> readb :: [char]->[char] ||defined internally + +_r_e_a_d_v_a_l_s is a family of functions for reading a list of values from a +file. See manual section 31/3. + +`rep' applied to a number and a value, returns a list containing the +specified number of instances of the value. (The name is short for +`replicate'.) Example + rep 6 'o' = "oooooo" +See also `repeat'. + +> rep :: num->*->[*] +> rep n x = take n (repeat x) + +`repeat' applied to a value returns an infinite list, all of whose +elements are the given value. + +> repeat :: *->[*] +> repeat x = xs +> where xs = x:xs + +`reverse' applied to any finite list returns a list of the same elements +in reverse order. + +> reverse :: [*]->[*] +> reverse = foldl (converse(:)) [] + +`rjustify' applied to a number and a string, right justifies the string +in a field of the specified width. + +> rjustify :: num->[char]->[char] +> rjustify n s = spaces(n - # s)++s + +`scan op r' applies `foldl op r' to every initial segment of a list. +For example `scan (+) 0 x' computes running sums. + +> scan :: (*->**->*)->*->[**]->[*] +> scan op = g +> where +> g r = (r:). rest +> where +> rest [] = [] +> rest (a:x) = g (op r a) x + +There is another way to explain `scan', which makes it clearer why it is +useful. Let s0 be the initial state of an automaton, and +f::state->input->state, its state transition function - then `scan f s0' +is a function that takes a list of inputs for the automaton and returns +the resulting list of states, starting with s0. + +`seq' applied to two values, returns the second but checks that the +first value is not completely undefined. Sometimes needed, e.g. to +ensure correct synchronisation in interactive programs. + +> seq :: *->**->** ||defined internally + +_s_h_o_w is a keyword denoting a family of functions for converting values +of different types to their print representations. See manual section +23 for more details. + +`shownum' applied to a number returns as a string a standard print +representation for it. A special case of the operator `show'. Applied +to fractional numbers `shownum' gives 16 significant figures (less any +trailing zeros), using a format appropriate to the size of number. For +more detailed control over number format see `showfloat', `showscaled'. + +> shownum :: num->[char] ||defined internally, + +`showhex', `showoct' applied to an integer return its hexadecimal or +octal representation as a string. Note that showhex will also convert +floating point numbers to hexdecimal format as per the C 2011 standard. +Example + showhex pi => 0x1.921fb54442d18p+1 +the scale factor in p is a power of 2 (oddly, this part is in decimal). + +> showhex, showoct :: num->[char] ||defined internally + +`showfloat p x' returns as a string the number x printed in floating +point format, that is in the form "digits.digits", where the integer +p (>=0) gives the number of digits after the decimal point. + +> showfloat :: num->num->[char] ||defined internally, + +`showscaled p x' returns as a string the number x printed in scientific +format, that is in the form "n.nnnnnne[+/-]nn", where the integer p +(>=0) gives the number of digits required after the decimal point. + +> showscaled :: num->num->[char] ||defined internally, + +`sin' is the trigonometric sine function, argument in radians. + +> sin :: num->num ||defined internally + +`snd' returns the second component of a pair. + +> snd :: (*,**)->** +> snd (a,b) = b + +`sort' applied to any finite list sorts the elements of the list into +ascending order on the built in '<' relation. Note that you cannot sort +a list of functions. Example + sort "hippopotamus" = "ahimoopppstu" +The following definition uses merge-sort, which has n log n worst-case +behaviour. + +> sort :: [*]->[*] +> sort x = x, if n<=1 +> = merge (sort(take n2 x)) (sort(drop n2 x)), otherwise +> where +> n = # x +> n2 = n div 2 + +`spaces' applied to a number returns a list of that many spaces. + +> spaces :: num->[char] +> spaces n = rep n ' ' + +`sqrt' is the square root function on (integer or fractional) numbers. +The result is always fractional. + +> sqrt :: num->num ||defined internally + +`subtract' is a name for (converse) infix minus. Needed because you +cannot form postsections in `-'. (See manual page 9 on `sections'.) +Example + subtract 3 +is the function that subtracts 3. + +> subtract :: num->num->num +> subtract x y = y - x + +`sum' applied to list of numbers returns their sum. + +> sum :: [num]->num +> sum = foldl (+) 0 + +`sys_message' is an algebraic type containing a family of constructors +used to control output to UNIX files. See manual section 31/2 on Output +to UNIX files. The binary versions Stdoutb etc are used to write binary +data in a UTF-8 locale, see section 31/9 for more information. + +> sys_message ::= Stdout [char] | Stderr [char] | Tofile [char] [char] | +> Closefile [char] | Appendfile [char] | System [char] | +> Exit num | Stdoutb [char] | Tofileb [char] [char] | +> Appendfileb [char] + +`system' applied to a string causes the string to be executed as a UNIX +shell command (by `sh'). The result returned is a 3-tuple, comprising +the standard_output, error_output, and exit_status respectively, +resulting from the execution of the UNIX command. See manual section +31/1 on Input from UNIX files etc for more details. + +> system :: [char]->([char],[char],num) ||defined internally + +`take' applied to a number and a list returns the specified number of +elements from the front of the list. If the list has less than the +required number of elements, `take' returns as many as it can get. +Examples + take 2 [1,2,3,4] = [1,2] + take 7 "girls" = "girls" + +> take :: num->[*]->[*] ||defined internally, as below + + take (n+1) (a:x) = a:take n x + take n x = [], if integer n + = error "take applied to fractional number", otherwise + +`takewhile' applied to a predicate and a list, takes elements from the +front of the list while the predicate is satisfied. Example: + takewhile digit "123gone" = "123" + +> takewhile :: (*->bool)->[*]->[*] +> takewhile f [] = [] +> takewhile f (a:x) = a:takewhile f x, if f a +> = [], otherwise + +`tinynum' is the smallest positive fractional number that can be +distinguished from zero in this implementation (should be around 1e-324 +for IEEE standard 64 bit floating point). + +> tinynum :: num ||defined internally + +`tl' applied to a non empty list returns the list without its first +element. Example, tl "snow" is "now". + +> tl :: [*]->[*] +> tl (a:x) = x +> tl [] = error "tl []" + +`transpose' applied to a list of lists, returns their transpose (in the +sense of matrix transpose - rows and columns are interchanged). Example + transpose [[1,2,3],[4,5,6]] = [[1,4],[2,5],[3,6]] +The following definition is slightly more subtle than is at first sight +necessary, in order to deal correctly with `upper triangular' matrices. +Example + transpose [[1,2,3],[4,5],[6]] = [[1,4,6],[2,5],[3]] + +> transpose :: [[*]]->[[*]] +> transpose x = [], if x'=[] +> = map hd x':transpose(map tl x'), otherwise +> where +> x' = takewhile (~=[]) x + +It might be thought that this function belongs in a specialised library +of matrix handling functions, but it has been found useful as a general +purpose list processing function, whence its inclusion in the standard +environment. + +`undef' is a name for the completely undefined value. Any attempt +access it results in an error message. Note that `undef' belongs to +every type. + +> undef :: * +> undef = error "undefined" + +`until' applied to a predicate, a function and a value, returns the +result of applying the function to the value the smallest number of +times necessary to satisfy the predicate. Example + until (>1000) (2*) 1 = 1024 + +> until :: (*->bool)->(*->*)->*->* +> until f g x = x, if f x +> = until f g (g x), otherwise + +`zip2' applied to two lists returns a list of pairs, formed by tupling +together corresponding elements of the given lists. Example + zip2 [0..3] "type" = [(0,'t'),(1,'y'),(2,'p'),(3,'e')] +This function is often useful in list comprehensions, where it provides +an idiom for traversing two lists in parallel. For example the +following expression returns the scalar product of x and y (x,y::[num]) + sum [ a*b | (a,b) <- zip2 x y ] + +> zip2 :: [*]->[**]->[(*,**)] ||defined internally, as below + + zip2 (a:x) (b:y) = (a,b):zip2 x y + zip2 x y = [] + +Note that if the lists being zipped are of different lengths, the length +of the result is that of the shortest list (this holds for zip2 and all +the following zip functions). + +The function `zip3' is analogous but takes three lists and returns a +list of 3-tuples. Similarly for `zip4', `zip5', `zip6' - zip functions +above zip6 are not provided in the standard environment. + +> zip3 (a:x) (b:y) (c:z) = (a,b,c):zip3 x y z +> zip3 x y z = [] +> zip4 (a:w) (b:x) (c:y) (d:z) = (a,b,c,d):zip4 w x y z +> zip4 w x y z = [] +> zip5 (a:v) (b:w) (c:x) (d:y) (e:z) = (a,b,c,d,e):zip5 v w x y z +> zip5 v w x y z = [] +> zip6 (a:u)(b:v)(c:w)(d:x)(e:y)(f:z) = (a,b,c,d,e,f):zip6 u v w x y z +> zip6 u v w x y z = [] + +The following is included for compatibility with Bird and Wadler (1988). +The normal Miranda style is to use the curried form `zip2'. + +> zip :: ([*],[**])->[(*,**)] +> zip (x,y) = zip2 x y + +End of definitions of the standard environment + -- cgit v1.2.1