Funes, an interpreter for a Lisp dialect.
Copyright (c) 2004, 2005 Pablo Barenbaum <pablob@starlinux.net>

-- INSTALLING

Hans Boehms' Conservative Garbage Collector is required to
compile Funes. You also need gcc, bison and flex.

After building the GC library, edit the Makefile and change
the GC_PATH accordingly.

There is no configure script, and no make install. Just make,
and then try:

./fu

to enter the toplevel. Also,

./fu <file> [<args>]

loads the given source file and then exits.


-- SOME EQUIVALENCES

GENERAL EQUIVALENCES

Scheme			Common Lisp		Funes
-----------------------------------------------------
lambda			lambda			fun
define			--			def
--			defun			defun
set!			setf			set
eq?			eq			eq
#t			t			#t
#f			(), nil			(), #f
()			(), nil			(), #f
named let		--			nlet
apply			apply			call
begin			progn			do
if, cond		if, cond		if C_1 T_1 ... C_N T_N [ELSE]
--			read-from-string	stread
read-line		read-line		input

The operator fun creates a lexical scoped function.
There's also a dynamic lambda (dyn) which creates a
dynamic scoped anonymous function, and defdyn, 
analogous to defun for dynamic functions.

BASIC TYPES

Scheme			Common Lisp		Funes
-----------------------------------------------------
#\a			#\a			\a
...
integer->char		--			chr
char->integer		--			ord

There's only support for integers. The operations are
standard: +, -, *, quotient, %, remainder, modulo.

MACROS

Scheme			Common Lisp		Funes
-----------------------------------------------------
--			defmacro		macro
--			gensym			gensym

TYPE PREDICATES

Scheme			Common Lisp		Funes
-----------------------------------------------------
pair?			consp			<cons>, consp
integer?		integerp		<int>
string?			stringp			<str>
char?			characterp		<char>
vector?			vectorp			<vec>

SEQUENCES

Many of these functions (copy, reverse, cat, etc.) work not only
on lists but also on other types of sequences: currently, vectors
and strings.

Scheme			Common Lisp		Funes
-----------------------------------------------------
--			acons			acons
list*, cons*		list*			list*
list-ref		nth			nth (lists), elt (generic)
list-tail		nthcdr			ntl
last-pair		last			last
memq, memv, member	member			member ELT LIST [EQ-PRED=eq]
assq, assv, assoc	assoc			assoc ELT ALIST [EQ-PRED=eq]
vector			vector			vec
vector-ref		aref			vref
make-vector		--			mkvec
--			defstruct		defstruct
length			length			len
string-append		concatenate		cat
reverse			reverse			rev
reverse!		nreverse		xrev
copy-tree		copy-tree		copy
--			some			any
--			every			all
--			notany			not-any
--			notevery		not-all

Moreover:

index <e> <s> [<pred>]	returns the first position P of the
			sequence <s> such that (<pred> <e> (elt P <s>))
			by default, <pred> = eq
join <sep> . <seqs>	joins the sequences in a new sequence,  
     			separating them with <sep>
			E.g.:
			(join "+" "abc" "def" "ghi") -> "abc+def+ghi"
range			Python-like range
iota			SRFI-like iota

OUTPUT and FORMATTING

Scheme			Common Lisp		Funes
-----------------------------------------------------
display			princ			pr, pr1 (no newline)
write			print			wr, wr1 (no newline)
newline			--			lf, cr
(format #f ...)		(format nil ...)	fmt
(format #t ...)		(format t ...)		prf

MAPPING

Scheme			Common Lisp		Funes
-----------------------------------------------------
map			mapcar			map
for-each		mapc			mapc
--			maplist			maplist
--			mapl			mapl
--			map			mapt

LOOPING CONSTRUCTS

while <condition> . <body>
to <var> ([<start>] <end> [<step>]) . <body>
each <var> <seq> . <body>
for (<init> <condition> <step>) . <body>

HASHES

db {<key> <val>}*	makes a new hash associating key_1 with val_1, ...,
   			key_n with val_n; uses eq as the comparing function
mkdb [<n>]		makes a new hash of <n> buckets
data <hash> [<fun>]	returns a list of (<fun> (<key> . <val>))
			for all (<key> . <val>) pairs in <hash>
			by default, <fun> = #t (identity)
get <h> <k>		returns the pair (<key> . <val>) in the hash
			where (eq <key> <k>), and #f if the key is not
			in the hash
hget <h> <k>		returns the pair (<key> . <val>) in the hash
			where <key> and <k> are equal strings, and #f if
			the key is not in the hash
fget <ef> <hf> <h> <k>	returns the pair (<key> . <val>) in the hash
			where <key> and <k> satisfy (<ef> <key> <k>)
			(ef = "equality function"), and #f if there is
			none. hf is the "hash function" which, given
			a key and an integer n, returns an integer i,
			0 <= i < n. <hf> should satisfy that for any
			pair of keys k1, k2 that (<ef> <k1> <k2),
			(<hf> k1 i) = (<hf> k2 i) for all i.

EXCEPTIONS

handle <symbols> <thunk> <handler (symbol errval)>
catch <symbol> <thunk>
throw <symbol> [<errval>] = err <symbol> [<errval>]
try <symbols_1> <body_1> ... <symbols_n> <body_n> [<default>]

FILES and ENVIRONMENTS

Environments are hashes.

pack . <body>		executes the body and returns the
			resulting environment
module <name> . <body>	(def <name> (pack . <body>))
env			the current stack of environments
dir			the current environment
load <file>		as in Scheme or Common Lisp
import <file>		returns an environment
use <symbol>		(def <symbol> (import (fmt "%s.fu" <symbol>)))
run <file> . <args>	returns the value of the last evaluated expression
args			a list of arguments passed to the file
sys <string>		executes the string in the shell

RANDOM

rand <n>		a random integer between 0 and n
choice <l> [<n> <r>]	choices <n> elements from the list n
			iff r is #t, elements may be repeated;
			by default, n = 1, r = #f

There are still no means for changing the random seed.

SETTERS

setter <getter>		returns the current setter of the getter
			it may be defined or changed:
			(set (setter <getter>) ...)

Most getters have an associated setter. Funes doesn't have
Common Lisp's rplaca, rplacd, etc. or Scheme's set-car!,
set-cdr!, etc.

Instead one should do:

(set (car <pair>) <value>)

CONTAINERS AS FUNCTIONS

Sequences and hashes are implicit functions on their
indexes. They can be treated, literally, as if they were
functions.

E.g.:

(def l (list 'a 'b 'c))	-> (a b c)
(l 0) 			-> a
(set (l 0) 'x)		-> x
l			-> (x b c)
(map l '(2 1 2 0))	-> (c b c x)

DOTTED NOTATION

The lexer reads a symbol followed by a dot (with no
whitespace in between) and an expression as a list with
the identifier and the expression:

a.x = (a x)
a.b.(f x y z) = (a (b (f x y z)))	

This is particularly handy for hashes (also modules or
environments).

E.g.:

## File foo.fu

(def (fact n)
 (if (eq n 0)
  1
  (* n (fact (- n 1)))))

## And then...

(use foo)
(foo.fact 5)		-> 120

STRING INTERPOLATION

If a "$" is found in a string, the parser reads an expression
and then continues reading the string. The printed representation
of the value of the expression is interpolated.

E.g.:

"$1" -> "1"
(let ((a 5)) "$a") -> "5"
"$(* 10 2)" -> "20"

etc.

Moreover, if "$@" is found in a string, the parser reads two
expressions, the second of which should be a list. Then it 
prints the elements of the list joining them with the first
expression:

(let ((l (list 'a 'b 'c))) "$@", "l") -> "a, b, c"
"$@'+(list 1 2 3)") -> "1+2+3"

SOUND

snd [<freq> <duration> <rep> <delay>]
	makes a sound through the PC speaker
	of the given frequency <freq> in Hz and which
	lasts <duration> in milliseconds, it repeats
	it <rep> times with a delay of <delay> milliseconds.
	by default, freq = 220, duration = 100, rep = 1,
	delay = 0

KEYWORDS

Any symbol starting with "=" (*BUT* '=) evaluates to itself.

=foo	-> =foo

"KEYWORD" ARGUMENTS	

Keyword arguments use a somewhat different syntax (i.e.
comparing it to other Lisps), they do NOT use keywords.

To make a keyword argument, or to call the function with 
keywords arguments, just precede the name of the argument
with "--" and follow it with the [default] value.

E.g.:

(def (f x --y 'a --z 'b)
 (list x y z))

(f)			-> error (x not supplied)
(f 1)			-> (1 a b)
(f 1 2)			-> (1 2 b)
(f 1 2 3)		-> (1 2 3)
(f 1 --z 1000) 		-> (1 a 1000)
(f 1 --z 1000 'zut)	-> (1 zut 1000)
(f --z 1 --y 2 'bar)	-> (bar 2 1)
(f --y 1 2 'bar)	-> (2 1 bar)
