Lii

Lii is a declarative object-oriented mildly esoteric language created by User:Fergusq in 2014. It is named after a fictional 31st century tea company Lii Tea (from a SciFi book, I forgot the name). Language is a mix of functional and object-oriented programming.

Overview
In Lii, all objects are immutable and do not contain any fields. This means that all instances of a class are equal. New "values" are created by declaring new anonymous classes. All methods are side-effectless.

A traditional Hello World:

Main { main -> BS { "Hello World!"; } }

Here, class  with method   is declared. The method returns a  (  for short) object. The interpreter should output that string. This is the only way to output things in Lii.

Classes and methods
Classes have always a super class (default ). Methods have always a return type.

For example, a class that represents a function (for implementation of the  class, see examples):

Function { call(Natural val) -> Natural; }

Anonymous classes
-operator is used to create a new anonymous class instance.

^Function { call(Natural val) -> Natural { val.increment; } }

Built-in classes
Lii has a small standard library of important classes.

Object (O)
The base class of all classes. is an abstract method, calling it will raise an error.

Object : Object { class -> Class; toString -> BS; }

Class (C)
Represents a class. The base class of all metaclassses. Can be used with -operator to create a new anonymous class.

Class : Object {}

BasicString (BS)
Used for output. returns the string.

BasicString : Object { append(BasicString str) -> BasicString; toString -> BasicString; }

Computational class
This should be Turing complete, for example here are the implementations of SKI combinators:

Function { call(Function f) -> Function; } I : Function { call(Function x) -> Function { x; } } K : Function { call(Function x) -> Function { ^ Function { call(Function y) -> Function { x; } 		}; 	} } S : Function { call(Function f) -> Function { ^ Function { call(Function g) -> Function { ^ Function { call(Function x) -> Function { f.call(x).call(g.call(x)); } 				}; 			} 		}; 	} }

CLii
Influenced by F#, CLii is a less esoteric variant of Lii. Although syntax has been completely redesigned, the core runtime system is same as Lii's.

Main { main -> "Hello, world!" }

Another example:

Main { .factorial(n) -> if n = ^Natural{} then ^Natural{}.inc else .factorial(n.dec) * n 	main -> let test1 = .list let test2 = .fib(10).toString let test3 = .factorial(6).toString ""+test1+"\n"+test2+"\n"+test3 list -> let list = ^List{}.cons("world").cons("Hello, ") .. "!" 		list.toString fib(i) -> if i <= 1 then i else .fib(i - 1) + .fib(i - 2) }

Hello world
Main { main -> BS { "Hello world"; } }

Fibonacci sequence
Calculates fib(6).

Main { main -> BS { self.fib(^Natural{}.increment.increment.increment.increment.increment.increment).toString; }	fib(self m, Natural n) -> Natural { // Please note that 0.decrement returns 0. n.decrement.if(^Factory{			create->O {				m.fib(n.decrement).add(m.fib(n.decrement.decrement));			}		}, ^Factory{			create->O {				n;			}		}); } }

Natural numbers via linked lists
Factory { create -> O; }

Natural { link -> Natural; if(Factory f, Factory o) -> O { o.create; }	toString -> BS { "";	}	increment(self i) -> Natural { ^Natural { link -> Natural { i; }			if(Factory f, Factory o) -> O { f.create; }			toString -> BS { "*".append(i.toString); }			decrement -> Natural { self.link; }		};	}	decrement -> Natural { self; }	// Addition and subtraction using if function. There are possible better ways to implement using linked lists add(self a, Natural b) -> Natural { b.if(			^ Factory {				create -> O {					a.increment.add(b.decrement);				}			},			^ Factory {				create -> O {					a;				}			}		); }	subtract(self a, Natural b) -> Natural { b.if(			^ Factory {				create -> O {					a.decrement.add(b.decrement);				}			},			^ Factory {				create -> O {					a;				}			}		); } }

Tape via stacks
Main { main -> BasicString { ^ Tape { // Initialize tape, push some zeros to the stacks stack1 -> Stack { ^Stack{}.push(^ Natural) .push(^ Natural) .push(^ Natural); } 			stack2 -> Stack { ^Stack{}.push(^ Natural) .push(^ Natural) .push(^ Natural) .push(^ Natural); } 		// Example usage }.right.increment.increment.left.right.current.toString; } } Entry { prev -> Entry; next -> Entry; obj -> Natural; } Stack { first -> Entry; push(self stack, Natural o) -> Stack { ^ stack.class { first -> Entry { ^ Entry { next -> Entry { stack.first; } obj -> Natural { o; } }; 			} 		}; 	} 	pop(self stack) -> Stack { ^ stack.class { first -> Entry { stack.first.next; } 		}; 	} } Tape { stack1 -> Stack { ^ Stack; } stack2 -> Stack { ^ Stack; } current(self tape) -> Natural { tape.stack2.first.obj; } 	left(self tape) -> Tape { ^ tape.class { stack1 -> Stack { tape.stack1.pop; } stack2 -> Stack { tape.stack2.push(tape.stack1.first.obj); } }; 	} 	right(self tape) -> Tape { ^ tape.class stack1 -> Stack { tape.stack1.push(tape.stack2.first.obj); } stack2 -> Stack { tape.stack2.pop; } }; 	} 	increment(self tape) -> Tape { ^ tape.class { stack2 -> Stack { ^ Stack { first -> Entry { ^ tape.stack2.first.class { obj -> Natural { tape.stack2.first.obj.increment; } 						}; 					} 				}; 			} 		}; 	} 	decrement(self tape) -> Tape { ^ tape.class { stack2 -> Stack { ^ Stack { first -> Entry { ^ tape.stack2.first.class { obj -> Natural { tape.stack2.first.obj.decrement; } 						}; 					} 				}; 			} 		}; 	} }

Linked list
Main { main -> BS { ^List{}.cons("world").cons("Hello, ").append("!").toString; } }

// An empty pair List { car -> Object; cdr -> List; // = [o, l]	cons(self l, Object o) -> List { ^Pair { car -> Object { o; } cdr -> List  { l; } };	}	// = [o, []] append(self l, Object o) -> List { // This is same as cons, because the list is empty. See Pair for append for non-empty lists. ^Pair { car -> Object { o; } cdr -> List  { l; } // append = [o, [b, []]] };	}	toString -> BS { "";	} }

// A non-empty pair Pair : List { toString -> BS { self.car.toString.append(self.cdr.toString); }	// = [o, l.a(n)] append(self l, Object n) -> List { ^ self.class { cdr -> List { l.cdr.append(n); } };	} }