proj-oot-oot131027

i'd replace oot.txt but i don't wanna read thru the old stuff right now, so:

syntax

commentary: oot has a bunch of syntax but almost all of it is for grouping; it has few special forms for control constructs.

basic arithmetic operators (addition, subtraction, multiplication, division) are ++,-++,,-

exponentiation is ^^

basic comparisons (equals, less-than-or-equals, less-than, greater-than-or-equals, greater-than) are ===, <=, 1

elementOf (python's 'in') is <.

for the most part you can and should use == instead of ===. == behaves exactly like === except when its righthand argument is a type. == is 'isa', which parallels the English usage of 'A is a B', e.g. 'Bob is a Bob; Bob is a Human; Bob is a Animal; A Human is an Animal'. So 'a == b' means 'if a can be upcast to the type of b or b can be upcast to the type of a (type(a) < type(b) or type(b) < type(a)), then return a === b; otherwise, if b is not a type, raise a type error; otherwise, if b is a type that could contain things of kind a, otherwise, then return a <. b; otherwise, if a and b are both types of the same kind, return a < b; otherwise, return F'

e.g. the following each return T: 3 == 3; 3 == Int; Int == Num; Int == Type; and the following each return F: 3 == 5; 'hi' == Int; Str == Num; 3 == Tuple. todo is are Str == Num and 3 == Tuple really that different?

the reason for calling 'isa' == is to make it easy enough to type so that you use it in preference to === in 'if' statements. For example, you can say "if exception1 == blahExceptionType", and then later you might want to create a subclass of blahExceptionType called blahBlahExceptionType, and this condition will still return True if 'exception1' is a blahBlahExceptionType.

the presence or absence of whitespace matters, but not the amount (except that the presence or absence of a blank line matters).

whether or not there is a space between an operator and a symbol matters (unattached vs. attached)

all infix operators must first be functions, which are then bound to an infix operator

to turn an binary infix operator into a binary function, surround it by parens, e.g. (++) actually we dont need this right? b/c all infix ops must first be functions

to turn a binary function into a binary infix operator (infixification), surround it by <>s, e.g. f a b -> a <f> b actually maybe *f* is better, because infixified operators will be at the * precedence level

to turn a trinary function f into a trinary infix operator (infixification), use <f

f>, e.g. f a b c -> a <fb f> c

() and {} for grouping.

each line is implicitly surrounded by ()s unless it has more opening parens than closing parens within it

a blank line, or a closing }, implicitly closes all remaining parens (but not {}s)

boundaries look like this: boundaryName blah blah boundaryName

annotations look like this: f^immutable (f has the property 'immutable') or this: f^arity/2 (f's arity is 2) or this: ^{immutable; arity/2} (a block of annotations)

all symmetric-looking operators must be associative

functions are left associative, and there is curried partial function application like in haskell

todo: what did we decide to do with when we close functions from further optional keyword arguments?

x.f.g means (g (f x))

<x >, where x is something, is character-level meta escape, e.g. <r blah > is the regex blah. <python > is python code.

<x:y y>, where x and y are something, is character-level meta escape with a y> terminator, e.g. <regex:end blah end> is the regex blah. <python:end end> is python code, <":end blah end> is a docstring.

"hi there" is a string

r"hi there" is a raw string

' is an operator regarding exceptions and maybe

prefixing a word with . is a shortcut making it a string, e.g. .blah = "blah"

to pass keyword arguments, use / , e.g. f positionalArg1 positionalArg2 .keyword1/value1 .keyword2/value2

an alternate, multiline syntax is to surround a bunch of things with {} and to use : to delimit arguments, e.g. the previous example could also be written:

f { positionalArg1 : positionalArg2 keywordarg1: value1 keywordarg2: value2 }

this is equivalent to (f {positionalArg1} {positionalArg2} "keyword1"/{value1} "keyword2"/{value2}).

The idea is that if you see any thing like : or blah:, these things break their enclosing block into pieces, implicitly grouping everything between them. Note that positionalArg1, value1, and value2 are blocks that are implicitly enclosed by {}s and hence may range over multiple lines.

a useful example of this is:

if { condition then: first else: second }

which is the same as (if {condition} .then/{first} .else/{second})

single commas are for separating multiple return arguments. Some functions may return optional return values which are ignored if not captured:

max_val = max list1 max_val, argmax_pos = max list1

Return values can be captured by name. 'max' returns val, pos:

.pos/argmax_pos = max list1

single commas also group together everything in between them, and between them and enclosing ()s.

multiple commas are for finer groupings. ,, groups in between ,s, ,,, groups in between ,,s, etc. It's similar to :s but they group up to enclosing () groups, not to enclosing braces todo this makes things hard to copy and paste, doesn't it? or does the 'enclosing ()' make it easy, because this usually stops at EOL? e.g. a , b ,, x ,, y ,, z, c is the same as a , b (x) (y) (z), c

todo: are commas really different from the above colons?

what function definitions looks like:

full: funcname = return args `args` fn_body implicit args: funcname = return args `` fn_body_with_implicit_args one anonymous return arg: funcname = `args` fn_body_with_implicit_args anonymous: (`` fn_body_with_implicit_args)

what function calling with keywords looks like:

  f .bob/3 .harry/4

what pattern matching assignment looks like:

  a .bob/b .harry/c = [1 2 .harry/3 .bob/4 5]  /// a==1, b==4, c==3

note that now we can still use a/b to denote a directed arc in data.

operator precedence proposal:

Precedence Operator 8 . (note: in haskell this is looser than fn application) (right associative) 7 function application (left associative) 6 all unary operators 5.5 exponentiation 5 (and most everything else) 4 ++ 3.5 +++, cons (dunno about this one; in Haskell they are a lower level than addition, also right associative) 3 === ~=== == ~== < <= > >= <...

...> (trinary ops)
    2             && || (in haskell these are right-associative but i think i'll make them non-associative)
    1.5           $, >> (haskell's $ and >>, i mean) (in haskell these are right-associative)
    1             = (not really an operator)
    0             other stuff that is not operators

-x is the same precedence as x, e.g. -+ (subtraction) is the same as ++ (addition)

note: within these levels, stuff is non-associative and requires explicit parens, unless it is one operator repeated and it associates todo: is . really right associative?

operator precedence by first char:

Precedence Operator 8 . (note: in haskell this is looser than fn application) (right associative) 7 function application (left associative) 6 all unary operators 5 * (and most everything else) 4 + 3.5 +++, cons (dunno about this one; in Haskell they are a lower level than addition, also right associative) todo 3 = < > except that single =s is level 1, see below 2 &

(in haskell these are right-associative but i think i'll make them non-associative)
    1.5           $, >> (haskell's $ and >>, i mean) (in haskell these are right-associative)  todo
    1             = (not really an operator)
    0             other stuff that is not operators

~ is 'not'

~= does not exist.

[] is for data todo

within data, ;s are for matrix literals: [1 2 3 : 4 5 6 : 7 8 9]

for 3-dimensional matrices, use ;- to delimit planes. For 4d, use ;--, etc. E.g.:

[1 2 3 ; 4 5 6 ; 7 8 9 ;- 10 11 12 ; 13 14 15 ; 16 17 18 ;- 19 20 21 ; 22 23 24 ; 25 26 27]

[" ] is autostrigified data

[" alice bob] == [ "alice" "bob" ] (note: a list is like a network where the nodes are named only 0,1,2,...)

[. ] is autokeyworded data

[. 2 alice/3 bob/4] is [2 "alice"/3 "bob"/4]

todo shouldn't we use : to denote nodes, rather than keywords?? or is that not any different if we consider a 'root' node, e.g.

[. node1: [2 alice/3 bob/4]/node2 [2 alice/4 bob/4]/node3 node2: /node3 /node1 node3: /#{#label_label /.label_of_arc_from_node3_to_node1}node1 label_label: /.label_of_arc_from_node3_to_node1 ]

this defines a 3-node network. node1 has two outgoing arcs, both 4-ary hyperarcs. the first hyperarc has src=node1, 0=2, "alice"=3, "bob"=4, target=node2. the second hyperarc has src=node1, 0=2, "alice"=4, "bob"=4, target=node3. node2 has two outgoing non-hyper (2-ary) arcs whose source is node2 and whose targets are node3 and node1 respectively. node3 has one outgoing 2-ary arc whose target is node1 and whose label is "arc_from_node3_to_node1". the arc connecting node3's outgoing arc to its label itself has a label, which is a node with one outgoing edge, "label_of_arc_from_node3_to_node1". We didn't count this node when we said it was a 3-node network because it is identicaly to an arc of an arc attached to a base node.

note that within annotatations or ^^s in data, everything is a keyword by default. to variablize something, prefix with ?; to interpolate a value, use $.

todo: shouldn't we save ^^ for exponentiation and find something else for labeling? maybe # for labeling?

to interpolate within strings or macros or keyworded data, prefix with $

; for EOL terminator

;; for EOL comment

;< >; for multiline commment

capitalization: capitalized and lowercase words are treated the same, except that hygenic macros and most other metaprogramming constructs can only access the string representation of identifiers which are capitalized. E.g. you know how in Ruby on Rails, it introspects on the name of some classes to decide which tables they correspond to? This sort of thing could only be done with capitalized identifiers in Oot. This gives the reader a clue which identifiers are just arbitrary names and which ones have semantics being assigned by some metaprogramming framework.

todo translate this example:

make-fsm = fsm `s0 reset-event state-transitions ` "creates an fsm with initial state s0, a reset event, and a map of transitions. [state-transitions] must be a map of state->[[f1 f2 ...] {e0->s0, e1->s2, ...}]" s = atom s0 fsm = `evt` { if (evt == reset-event) { println "Reset event, returning to " s0 swap! s (`_` s0) : actions, transitions = state-transitions @s if-let [new-state/(transitions evt)] { println "Event" evt "causes transition from" @s "to" new-state doseq [f actions] (f) swap! s (`_` new-state) : println "Unexpected/unhandled event" evt "in state" @s } }}

literals

oot fundamental attributes and capabilities

todo

perspectives

todo

pointers, references

todo

interfaces

todo

laziness

composite types

synonym, sum, product, struct

type constructors

patterns

exceptions

primitive operations

traverse arc traverse reified arc

what else?

constraint satisfaction/logic programming

grammar (perl6 rules/OMeta), oot pattern

(see also http://en.wikibooks.org/wiki/Introduction_to_Programming_Languages/Logic_Grammars )

basic types of computation supported by oot:

various DSLs regarding data with overlap:

see the basic word lists in ootNotes5.


Footnotes:

1. , >=,