||KRC prelude, D. A. Turner, April 2016
||This is a new prelude written for the Unix version of KRC, mostly
||borrowed from the preludes of Miranda and/or Haskell
abs :- takes the absolute value of a number, e.g. abs (-3) is 3;
abs x = x, x >= 0
= -x

all :- applied to a predicate (truth-valued function) and a list
returns "TRUE" if the predicate holds for every element;
all f = and . map f

and :- applied to a list of truthvalues, takes the logical conjunction;
and = foldr '&' "TRUE"

any :- applied to a predicate and a list returns "TRUE" if the
predicate is "TRUE" for at least one element of the list;
any f = or . map f

bool :- predicate, returns "TRUE" on the strings "TRUE" and "FALSE",
"FALSE" on other values;
bool x = x=="TRUE" | x=="FALSE"

char :- predicate, true on strings of size one, false otherwise
(defined in machine code);

chr :- `chr n' is ascii character number n, e.g. chr 10 == "\n"
(defined in machine code);

cjustify :- applied to a number and a string, centre justifies the
string in a field of the specified width;
cjustify n x = cjustify' (n - printwidth x) x

cjustify' :- used by cjustify;
cjustify' n x = [spaces (n / 2),x,spaces ((n + 1) / 2)]

curry :- converts a function that expects a 2-list into a function
that takes its arguments one at a time;
curry f a b = curry f [a,b]

curry_ :- generic, converts a function expecting an n-list into the
corresponding n-ary function. Example: curry = curry_ 2.
Unlike generic uncurry, curry_ needs to be given n;
curry_ 0 f = f []
curry_ n f = curry_' n f

curry_' :- used by curry_, it is introduced to get round the rule
that a KRC function must have the same number of formal
parameters in each of its defining equations;
curry_' n f a = curry_ (n-1) (f . (':' a))

concat :- applied to a list of lists, joins them into a single list
with `++', e.g.
concat [[1,2],[3,4]] = [1,2,3,4];
concat = foldr '++' []

const :- creates constant functions, e.g (const 3) is a function that
always returns 3;
const a b = a

digit :- predicate, true on single digit strings;
digit x = char x & "0" <= x <= "9"

digitval :- returns the numeric value of a digit;
digitval x = ord x - ord "0", digit x

drop :- `drop n x' returns list x without its first n elements;
drop n x = x, n <= 0
drop n [] = []
drop n (a:x) = drop (n - 1) x

dropwhile :- `dropwhile f x' removes elements from the front of list x
for which function f returns "TRUE";
dropwhile f [] = []
dropwhile f (a:x) = dropwhile f x, f a
= a:x
elem :- applied to a value and a list returns "TRUE" or "FALSE" as the
value is or not present in the list;
elem = flip member

even :- predicate, true on even numbers;
even n = n % 2 == 0

error :- applied to a printable value, terminates the program and
prints the value with (!) on stderr.
(defined in machine code);

explode :- explodes a string into a list of characters
(defined in machine code);

filter :- applied to a predicate and a list returns a list of the
elements for which the predicate takes value "TRUE";
filter f x = {a|a<-x;f a}

flip :- converts a two-argument function into one that takes its
arguments in the opposite order;
flip f a b = f b a

foldl :- folds up a list using a given binary operator and start
value in a left associative way.  Example:
foldl op r [a,b,c] = op c (op b (op a r))
In order to run in constant space, foldl evaluates
the accumulating result at each stage;
foldl op s [] = s
foldl op s (a:x) = strict (foldl op) (op a s) x

foldl1 :- folds left over non-empty lists;
foldl1 op (a:x) = foldl op a x

foldr :- folds up a list using a given binary operator and start
value in a right associative way.  Example:
foldr op r [a,b,c] = op a (op b (op c r));
foldr op s [] = s
foldr op s (a:x) = op a (foldr op s x)

foldr1 :- folds right over non-empty lists;
foldr1 op [a] = a
foldr1 op (a:b:x) = op a (foldr1 op (b:x))

function :- type testing predicate
(defined in machine code);

hd :- applied to a non empty list, returns its first element;
hd (a:x) = a

id :- is the identity function, applied to any object it returns it;
id a = a

implode :- takes a list of strings and joins them together to make a
single string - the opposite of explode
(defined in machine code);

init :- applied to a non-empty list returns the list without its last
element;
init [a] = []
init (a:x) = a : init x

interleave :- merges two lists into one by taking members from them
alternately;
interleave (a:x) y = a:interleave y x
interleave [] y = y

intersect :- returns a list of the common elements of two lists;
intersect x y = filter (member x) y

iterate :- (iterate f x) is the infinite list [x,f x,f(f x), ... ];
iterate f x = x : iterate f (f x)

last :- applied to a non-empty list returns its last element;
last x = x (#x-1)

lay :- applied to a list formats it to have one element per line when
printed with !;
lay [] = []
lay (a:x) = show a:"\n":lay x

layn :- similar to `lay', but produces output with numbered lines;
layn x = layn' 1 x

layn' :- (layn' n x) formats list x one element per line with lines
numbered starting at n;
layn' n [] = []
layn' n (a:x) = rjustify 4 n:")  ":show a:nl:layn' (n + 1) x

length :- a function with same action as unary `#';
length x = #x

letter :- predicate, true on single letter strings;
letter x = uppercase x | lowercase x

limit :- finds the fixed point, if any, of a function repeatedly applied
to an initial value;
limit f x = limit f (f x), f x \= x
= x

list :- type testing predicate
(defined in machine code);

listdiff :- defines the action of the "--" operator;
listdiff [] y = []
listdiff x [] = x
listdiff (a:x) (b:y) = listdiff x y, a == b
= listdiff (a:listdiff x [b]) y

ljustify :- applied to a number and a string, left justifies the string
in a field of the specified width;
ljustify n x = [x,spaces (n - printwidth x)]

lowercase :- predicate, true on lowercase letters;
lowercase x = char x & ord "a" <= ord x <= ord "z"

map :- applied to a function and a list returns the list obtained by
applying the function to each element;
map f x = {f a|a<-x}

max :- returns the greater of two numbers or two strings under '>=';
max a b = a, a>=b
= b

maximum :- of a list of numbers or strings returns the greatest;
maximum = foldl1 max

member :- applied to a list and a value returns "TRUE" or "FALSE" as the
value is or not present in the list;
member [] a = "FALSE"
member (a:x) b = a == b | member x b

merge :- of two ordered lists merges them to a single ordered list;
merge x [] = x
merge [] y = y
merge (a:x) (b:y) = a:merge x (b:y), a <= b
= b:merge (a:x) y

min :- returns the lesser of two numbers or two strings under '<=';
min a b = a, a<=b
= b

minimum :- of a list of numbers or strings returns the least;
minimum = foldl1 min

mkset :- removes duplicate elements from a list, takes time quadratic in
the length of the list;
mkset x = mkset' x []

mkset' :- used by mkset;
mkset' [] y = []
mkset' (a:x) y = mkset' x y, member y a
= a:mkset' x (a:y)

neg :- a function with same action as unary `-';
neg x = -x

nl :- newline;
nl = chr 10

not :- a function with same action as unary `\';
not x = \x

np :- newpage;
np = chr 12

number :- type testing predicate
(defined in machine code);

odd :- predicate, true on odd numbers;
odd n = \even n

or :- applied to a list of truthvalues, takes their logical disjunction;
or = foldr '|' "FALSE"

ord :- converts a character to its ascii number, e.g. ord "\n" == 10
(defined in machine code);

printwidth :- for any value returns its width on printing with "!",
width meaning number of characters
(defined in machine code);

product :- applied to list of numbers returns their product;
product = foldl '*' 1

quote :- quotation mark;
quote = chr 34

read :- takes a file or device name and returns a list of characters
(defined in machine code);

rep :- `rep n x' produces a list with n elements all of which are x;
rep n x = take n (repeat x)

repeat :- `repeat x' produces an infinite list of x's;
repeat x = x : repeat x

reverse :- applied to a list returns a list of the same elements in
reverse order;
reverse = foldl ':' []

rjustify :- applied to a number and a string, right justifies the string
in a field of the specified width;
rjustify n x = [spaces (n - printwidth x),x]

seq :- `seq x y' evaluates x and returns y
(defined in machine code);

show :- applied to any (non-function) value formats it to show its
structure when printed with !;
show x = x, number x
= ["\"",map showchar (explode x),"\""], string x
show [] = "[]"
show (a:x) = ["[",show a,{[",",show b]|b<-x},"]"]

showchar :- part of the workings of `show', for use on strings;
showchar c = c, 32 <= ord c < 127
showchar "\a" = "\\a"
showchar "\b" = "\\b"
showchar "\f" = "\\f"
showchar "\n" = "\\n"
showchar "\r" = "\\r"
showchar "\v" = "\\v"
showchar "\\" = "\\\\"
showchar "\"" = "\\\""
showchar c = ["\\",ord c]

sort :- of a list of numbers or strings returns an ordered list of the
same elements. This version of merge-sort is due to Ian Lynagh;
sort = sort' . map (flip ':' [])

sort' :- used by sort;
sort' [] = []
sort' [x] = x
sort' xs = sort' (sort'' xs)

sort'' :- used by sort, Ian Lynagh calls this function merge_pairs;
sort'' [] = []
sort'' [x] = [x]
sort'' (x:y:xs) = merge x y : sort'' xs

spaces :- applied to a number returns a list of that many spaces;
spaces 0 = []
spaces n = " ":spaces (n - 1)

strict :- applied to a function returns a version of the function that
always evaluates its argument;
strict f x = seq x (f x)

string :- type testing predicate
(defined in machine code);

sum :- applied to list of numbers returns their sum;
sum = foldl '+' 0

tab :- horizontal tab;
tab = chr 9

take :- `take n x' returns a list of the first n elements of list x;
take n x = [], n <= 0
take n [] = []
take n (a:x) = a : take (n - 1) x

takewhile :- `takewhile f x' takes elements from the front of list x for
which function f returns "TRUE";
takewhile f [] = []
takewhile f (a:x) = a : takewhile f x, f a
= []

tl :- applied to a non-empty list returns the list without its first
element;
tl (a:x) = x

uncurry :- generic uncurry, converts an n-ary function into a
function that takes its arguments as an n-list;
uncurry f [] = f
uncurry f (a:x) = uncurry (f a) x

union :- returns a merger of two lists with duplicates removed;
union x y = mkset (interleave x y)

until :- of predicate, function and value, applies the function to
the value until the predicate is satisfied;
until f g x = x, f x
= until f g (g x)

uppercase :- predicate, true on uppercase letters;
uppercase x = char x & ord "A" <= ord x <= ord "Z"

vt :- vertical tab;
vt = chr 11

write :- used to mark items to be sent to a file on output with !
write "filename" x
where x is any KRC data item.
(defined in machine code);

zip :- applied to a list of lists, returns the matrix transpose
i.e. rows and columns are interchanged.  Example
zip [[1,2,3],[4,5,6]] = [[1,4],[2,5],[3,6]]
also accepts upper triangular matrices, e.g.
zip [[1,2,3],[4,5],[6]] = [[1,4,6],[2,5],[3]];
zip x = zip' (takewhile ('\=' []) x)

zip' :- used by zip;
zip' x = [], x==[]
= map hd x : zip (map tl x)

zipwith :- applies an n-ary function to each row of a matrix with
n columns. Taking a 3-ary function f as example
zipwith f [x,y,z]
= [f (x 0) (y 0) (z 0), f (x 1) (y 1) (z 1), ... ];

zipwith f xss = map (uncurry f) (zip xss)