eevo

Tisp is a strong dynamically typed language (with a powerful first-class static type system in the works) inspired mostly by Scheme, with ideas from Lua, Python, Haskell, Julia, and Elm as well.

General

Comments

Comments start with a semicolon (;) and continue until the end of the line

Example: println "Hello World" ; ingnored by tisp until end of line.

Note: While many scripting languages use #, tisp adopts semicolons for easier keyboard accessibility, encouraging frequent use.

Types

Types are the nouns of Tisp, they represent the different kinds of expressions that Tisp can describe and transform.

Numbers

Integers

Whole numbers with optional + or - prefixes. Supports scientific notation with e or E followed by another integer.

Note: The exponent should be a positive integer, it can also be negative but that would just round to zero for integers.

Examples: 1, -48, +837e4, 3E2.

Decimals

Floating-point numbers, denoted with decimal point. Supports scientific notation with e or E followed by an integer.

Examples: 1., 0.018, +3.14, -.0054, 800.001e-3.

Rationals

Fraction type, a ratio of two integers. Same integer rules apply for numerator and dominator, without scientific notation.

Automatically simplified, and will through error on division by zero.

Examples: 1/2, 4/3, -1/12, 01/-30, -6/-3.

Booleans

True

All values except Nil are truthy, including explicit True, integers, strings, non-empty lists, etc.

Examples: True, 1, [8 7 6], "any string".

Nil

Nil represents false, or an empty list.

Examples: Nil, False, ().

Void

Represents the absence of a value. Used to force functions to return nothing or as a placeholder in lists.

Text

Strings

String of characters surrounded by double quotes ". Any character is valid, including newlines, except for double quotes and backslash which need to be escaped as \" and \\ respectively. Newlines and tabs can also be escaped with \n and \t

Examples: "foo", "foo bar", "string \"quoted\"", "C:\\windows\\path", "\tstring\twith white\n\tspace ".

Symbols

Case sensitive identifiers which are evaluated as variable names.

Valid characters include lower and upper case letters, numbers, and _+-*/\^=<>!?@#$%&~. They can not start with a number, and if the first character is a + or - then the second digit cannot be a number either.

Unlike other types, symbols are not self-evaluating, they resolve to their assigned value and throw an error if undefined.

Examples: foo, foo-bar, cat9, +, >=, nil?.

Collective Nouns

The basic types covered so far can be composed in multiple ways:

Pairs

A grouping of exactly two expressions in (fst ... rst) notation. fst is the first element and rst is the second element, either can be any type (including another pair) and do not have to be the same type.

When evaluated, the first element is a function, the rest are its argument, and the result is the function applied to the argument.

Examples: (1 ... 2), (f ... args)

Lists

Ordered sequences of expressions enclosed in parenthesis ( ) or brackets [ ] separated by white space. Made from chains of pairs ending in Nil (eg (1 2 3) = (1 ... (2 ... (3 ... Nil)))).

Lists denoted with parentheses are evaluated as function calls, while brackets are evaluated to lists (eg [1 2 3] = (list 1 2 3)).

The first element of a list can be placed before the parentheses to imitate more traditional function call syntax (eg f(x y z) = (f x y z)).

Examples: [1 2 3], (proton neutron electron), split(notes ","), (now)

Improper Lists

Chains of pairs where the last expression is not Nil.

Examples: (fry leela bender ... others), [1 2 3 ... 4]

Records

Records are unordered groupings of one or more key-value pairs separated by a colon and enclosed in curly braces. Sometimes called dictionaries, hash tables, structs, objects, or maps.

The key is a symbol which maps to a value of any type. Each value is evaluated when the record is defined. (In the future the key will also support any type, and the value will only be evaluated when the key is accessed, much like functions.)

Examples: { name: "Omar Little" age: (- 2008 1966) alive: False }

Functions

Functions take an input value and produce an output value. This happens by evaluating the function’s body expression with the given arguments added to the environment. The environment is captured when the function is defined, making functions closures.

Typically, the input value is a list of arguments. For example, the expression (inc 54) calls the function inc with a list of one value, the number 54, returning 55.

Examples: list, not, apply, map, sqrt, println

Primitives

Functions written in an external language other than tisp, such as the ones built-in to the language written in C. They behave like normal functions but are opaque, their implementation cannot be inspected within the language.

See built-ins section for more examples.

Examples: car, write, +

Macros

Functions that operate at the syntax level, accepting code as input and return code as output. Unlike functions they receive their arguments unevaluated, and return code that gets evaluated in the context the macro is called in.

This enables tisp to extend its own syntax, eliminate boilerplate, construct custom languages for specific tasks, or directly transform source code.

Examples: if, and, or, let

Forms

Macros written in an external language. Like macros, the arguments are not necessarily evaluated.

Examples: cond, def, quote

Procedures

Procedures are the verbs of tisp, they describe how expressions change. Procedures can be either functions, macros, primitives or forms.

Core procedures implemented in C and provided by default in the base environment

Convention: Procedures which return a boolean type should end with ? (eg pair?, integer?, even?), procedures with side-effects should end with ! (eg cd!, exit!)

car

Returns first element of given list.

cdr

Return rest of the given list, either just the second element if it is a pair, or another list with the first element removed.

cons

Creates a new pair with the two given arguments, first one as the car, second as the cdr. Can be chained together to create a list if ending with Nil.

quote

Prevents evaluation of an expression. Used to convert code to data, or create lists and symbols without evaluation.

Equivalent to single quote as prefix.

(quote x) ; returns the symbol x
'(a b c)  ; returns a list of 3 symbols, symbols do not get evaulated
'(* 3 4)  ; returns a list of 3 expressions, instead of 12

eval

Evaluates the expression given. Can be dangerous to use as arbitrary code could be executed if the input is not from a trusted source. In general apply should be used when possible.

=

Tests if values are all equal. Returns Nil if any are not, and True if they are.

cond

Evaluates each expression if the given condition corresponding to it is true. Runs through all arguments, each is a list with the first element as the condition which needs to evaluate to True, and the rest of the list is the body to be run if and only if the condition is met. Used for if/elseif/else statements found in C-like languages.

Also see if,when,unless,switch.

typeof

Returns a string stating the given argument’s type.

Func

Creates anonymous function, first argument is a list of symbols for the names of the new function arguments. Rest of the arguments to Func is the body of code to be run when the function is called.

Also see def.

Macro

Transformers which operate on syntax expressions, and return syntax. Similar to Func, Macro creates anonymous macro with first argument as macro’s argument list and rest as macro’s body. Unlike functions macros do not evaluate their arguments when called, allowing the expressions to be transformed by the macro, returning a new expression to be evaluated at run time.

Also see defmacro.

def

Create new symbol with the name of the first argument, and the value of the second. If the name given is a list use the first element of this list as a new functions name and rest of list as its arguments. If only one argument is given define a self evaluating symbol.

undefine!

Remove symbol from environment. Errors if symbol is not defined before.

defined?

Return boolean on if symbol is defined in the environment.

load

Loads the library given as a string.

error

Throw error, print message given by second argument string with the first argument being a symbol of the function throwing the error.

Differences From Lisp

Less Parenthesis

In tisp parenthesis are implied around every new line, and a line indented more than the previous one is a sub-expression of it. A line with only one expression stays that expression, not a list of length one. For example:

a b c
  d e
    f
  g h i

Becomes:

(a b c
   (d e
      f)
   (g h i))

Simpler

Tisp only has one builtin equality primitive, =, which tests numbers, text, lists, and objects which occupy the same space in memory, such as primitives.

Tisp is single value named, so procedures share the same namespace as variables. This way functions are full first class citizens. It removes the need for common lisp’s defunc vs defvar, let vs flet, and redundant syntax for getting the function from a symbol.

Symbols are case sensitive, unlike many other older lisps, in order to better interface with modern languages.

Read-Print Symmetry

By default Tisp’s output is valid Tisp code, fully equivalent to the evaluated input. Lists and symbols are quoted ((list 1 2 3) => '(1 2 3)), errors are comments. The only exception is anonymous functions/macros which will be supported soon. To print value as valid Tisp code use display and displayln, to get a plain output use print and println.