lists-jasper

jasper notes

see also [1]

mb should rename b/c java starts with j

go through rosetta stones

do just seq, not monadic het or nty, or unt or uty; hetrogeneous/untyped variable footnotes (1), (2) at EOL naw, mb #1, anywhere implied sequencing: "#1 stuff" means "do {#1; stuff}" "stuff #1" means "do {stuff; #1}" poor man's mixins? "debug" flavored footnotes (generalized: flavors) scoped (function or class scope) footnotes are an explicit substitute for AOP (aspect-oriented programming)'s "join points" the content of footnotes may simply be some tags which can be queried by an AOP pointcut, e.g. "' access_bank_account transfer" (i.e. an I-EXPR, in this example, a flat list with two elements), or it could be code (the default) (what's done with the return value? i guess the rest of the line, if there is any, is aborted if a certain flavor (i.e. product type coordinate value) of exception is thrown (or maybe special protocol for footnote return value?) two footnotes of the same # within scope mean that the footnote runs "around" the stuff in between, i.e. do bank_acct(a) = bank_acct(a) if a footnote is the only thing on a line, that's fine, but what if a footnote is specified in the middle of a line? is it just evaluated? like "foo bar #3 dude"? i guess this could mean "pass the default for this arg to #3 for advice, and let #3 do something again after this is called" pointcuts may query tags, but also can query the lexical scope of the footnote, including fn, class, module, and mb even source code file and version as wikipedia says about aspectJ, "Pointcuts can be composed and named for reuse". jasper itself should be used for this mb instead of letting a footnote at BOL be before, and at EOL be after, they should all be either middle or EOL, and this means the footnote can wrap (before or after)

	   footnotes do not have to be in order
	footnote tags can also be used for other purposes, i.e. http://en.wikipedia.org/wiki/Attribute-Oriented_Programming. should probably read http://en.wikipedia.org/wiki/A_Metadata_Facility_for_the_Java_Programming_Language
 stuff" means "do {#1; stuff}"
	         "stuff #1" means "do {stuff; #1}"

compiler can compile to various targets, like ruby, python, java

compiler can be told to inline and attempt to simplify a list of functions or modules or source filters-- helpful for when someone else wants to use some higher order stuff that looks like line noise to you. compiler is, basically, extremely modular, extensible, and IDE-friendly

(flavors? parameterized code? mb flavors determine which monads get added to everything?)

  1. at BOL for preprocessor (or do we need scoped preprocessing?? but can scope with whitespace, i.e.
  2. scoped preprocessor ) of course, preprocessor language is jasper
    1. is pre-pre processor, etc "meta" keyword for "macros"? or just preprocessor? sig whitespace and optional {} logical endpoint of sig whitespace: no : (python), ;, {} (C), "end" (ruby) needed! x=y defines x as convenience var x = y if q x = z x = x + 1 z = x / 2 -> z = x/2 where x = x'+1 x' = (if q {z} {x}) x = y continuations cot http://en.wikipedia.org/wiki/Continuation#Examples, i like how they say "Continuations are the functional expression of the GOTO statement, and the same caveats apply."

sub (or mac) like "where" in haskell everything prefix except a few predefined exceptions: arithmetic? naw.. these exceptions are converted to prefix before preproc/meta/macros see them $, $! (but $-, not $!) as in haskell (or mb --, since no shift is needed 4 that -- comments can be ) precedence of language keywords over user? of imports over later??? in import keyword? naw... no prec except language-defined! [] [[ instead of language spec, a ref implementation in itself

tupled return types , is sufficent, no need to surround with parens

dicts lisp lists (trees as linked lists) trees arrays (integer-indexed list with O(ln N) access), hashes (assoc arrays) iterators, generators graphs strings """ for "here" (parameterized) streams (for more, check other langs, don't forget *lisp) numbers: int rational ?? bool nil

data type flavors (such as "exact int", "fixed real", "float real", "exact float real") means a type which inherits from (i.e. is in the typeclass of) both "exact" and "int" clearly, "exact" is an empty typeclass

are class flavors like traits? http://en.wikipedia.org/wiki/Trait_%28abstract_type%29

containers have [] (naw, (), see below) [[x is short for [x] heck, why not just () instead of []? "call" the container? d = dict d(apple) = 3 pr d(apple) pr import "import std" assumed (unless "noimport std", which is discouraged) easy compiler cmdline to chain preprocessors (i.e. to let one source file preprocess another) can use the significant indentation to define data literals eg d = dict( apple 3 banana 2) (ie, look, no commas, no =s) (if you need to compute, use parens, e.g.: d = dict( apple 3 (whatever_kind_of_fruit_fred_gave_me) () ( the ()s, with opening parens followed by linefeed, are what distinguishes this from d = dict ({apple 3; banana 2;}), which would otherwise be assumed; surround block with {}, as in dict ({apple 3; banana 2;}), to pass a code block)

  umm, this is kinda like lisp, but more complex b/c the special case with (); why not just use '?
   d = dict
   '   apple 3
      banana 2
    nested_list =
    ' outermost_elem_1
      outermost_elem_2
        sublist_elem_1
          subsublist_elem_2
          subsublist_elem_2
	sublist_elem_3
    here_document =
      """hi
         dude
         multiline
         str
   or
    here_document = """hi dude multiline str """ or
    here_document ="""hi dude multiline str """ or
    here_document = """hidude multiline str"""

(initial compilation step removes HERE documents)

ptrs (store ptr that you get from elsewhere, even if you can't deref, or at least not easily)

syntaxes using =: "x = 3" assign value to convenience variable x

  "d = dict; d(bob) = 3"
    same as "_put d bob 3"
    (what if you did "(d(bob)) = 3"? should that be an error, or
     should it mean "lookup element bob in d, it should be a ptr, now
     	       	    deref that ptr and put 3 into that location",
     i.e. "*(d(bob)) = 3"? in other words, should l-values be
     ordinary expressions of type ptr, and "d bob" has an extra,
     special interpretation as type ptr, or do l-values have a special
     syntax involving "d(bob)"? seems like in the former case we are
     making this expression have a side-effect, namely a mutation; so
     maybe the latter is better; otoh, mb we should do the latter
     when we can, and the former otherwise, with the former requiring
     the type of the block to be side-effecty
     "(find_dict(1))(bob)" = 3 means, "_put find_dict(1) bob 3"
     in haskell, mutable arrays are in the IO monad or the ST monad

container protocol: get with default is just call w/ a pair arg, i.e. "d(bob,5)"?? no, what if multidim array? mb xtra comma or parens? comma: "d(bob,,5)" hmm, that could be useful in general for any call.. could supply default or raise exception with "f(bob,,5)" or "f(bob,,raise \"bad arg to function f\")", or, w/ footnote, "f(bob,,#1)"

also, support "properties" http://docs.python.org/library/functions.html#property

documentation and unittests within comments protocol or at least, help enable via docstring like reflection fns that parse I-exprs in docstring comments

something put together with parens without a space makes these two bind to each other as if surrounded by parens so "_put find_dict(1) bob 3" means "_put (find_dict(1)) bob 3", but "_put find_dict (1) bob 3" is an invocation of _put with 4 arguments

  same with other symbols UNLESS the combined string is defined, i.e. if "a+" is defined, then
  "a+" will mean a+, not "(a +)".

import import __ --- promiscuous by default import __ as name

automated attempted type coercion, using "to_" and "from_" fns (mb "to" and "from" should be keywords; "to int", "from int") (get error from haskell, look for "to", look for "from"?) but see also http://www.artima.com/forums/flat.jsp?forum=106&thread=179766&message=234456 ; "I also would recommend extreme caution in using that feature. People complain about dynamic typing and then go ahead and use implicit conversions. That is like filtering the mosquito and eating the camel. In 90% of the dynamic typing errors at least I get a type foo does not understand message bar message that makes it easy to find the error. With implicit conversions I can get all kind of logical errors without ever getting any hint at what is wrong. " so mb should have an operator meaning "coercion here, but i'm not going to tell you which one". of course, an IDE can query the compiler/interpreter to find out what it guessed -- ? ~? apparently scala already did something similar called implicit "conversions": http://www.artima.com/forums/flat.jsp?forum=106&thread=179766&start=0&msRange=15 * mb should use word "convert" or "implicit" to remind scala users * in the last example of the initial post on that thread, we wouldn't need to convert in haskell b/c we could just add an append fn w/ an array signature disallow multistep conversion paths (unless "~ ~", "~ ~ ~", etc or "~*" (!)) ambiguity error if multiple conversion choices

todo: learn about env, reader, writer, st monad in haskell, backtracing, continuations, syb in haskell, typeclassopedia, oohaskell (http://homepages.cwi.nl/~ralf/OOHaskell/), template haskell, liskell, hasp

can we get rid of the complexity of existential types? lazy patterns? make things open data by using typeclasses with default types? get rid of the complexity of "boxed" vs. "unboxed" (i think not, but mb syntactic support, with unboxed as default ("laz" keyword? btw laziness does change semantics (its not just optimization), b/c of "bottom") (also, we need fast string hashtables/assoc arrays, how does python do that, is it "boxed"?)? get rid of the complexity of monads (or at least, of monad transformers)? simplify arrows, other quasistd libs, typeclassopedia

if you want to hide the monads, do you really want to start with haskell? mb ocaml is what i seek, mb jasper unnecessary

can we simplify patterns? see all the weird stuff in http://www.haskell.org/tutorial/patterns.html

an "object class" is: typeclass with default type "object" is a value (whose type is its typeclass) "methods" are: syn sugas for functions on the default type that take an object of that type as first argument (which is hidden) (i.e. "self") "instance variables" are: entries in the association list inside the object (i.e. the value of the class type) "constructors" are: syntactic sugar, using the class's name, for a fn returning an object; this is better than using a data type literal because this way the actual data type (in haskell terms) can change "destructors" are: see http://eli.thegreenplace.net/2009/06/12/safely-using-destructors-in-python/. i think we shouldn't have destructors except for efficiency. use Python contexts http://www.python.org/dev/peps/pep-0343/

exception handling like python, see also Python contexts http://www.python.org/dev/peps/pep-0343/, java try finally see http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-errors , haskell exceptions optional "throws" that does nothing (helpful for IDEs) of course, everything has to be wrapped in some monad or another. i kinda like the "general" version of #6 in http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-errors should examine how erlang and ruby do it, too and how does a compiled language do this? C++, .NET (is this a language?), C#, F#, Mono (are the last 4 compiled?)

patterns a la haskell

vs haskell "haskell 4 dummies"/condecending? no, haskell for me! too verbose all those dummy vars having to annotate signatures which throw exceptions w/ monads too unreadable too much weird syntax (e.g. lazy patterns, non-prefix operators which may have precedence) yes, powerful, but means that you gotta learn all this before you can read someone else's code! this is why python wants "only one way to do it" if you want open data w/ typeclasses, must use a framework (syb? oohaskell?), or have lots of boilerplate too complex; even "gentle intro" isn't global namespace cluttered

namespaces hate having types, typeclasses, cluttering up global namespace. mangle. allow "overriding" of "methods" if using objects, then the hidden self argument of methods, and default types will disambiguate

logic programming to write type inference; even though will initially compile to haskell, ultimately want a concise "eval" written in itself

compiler API in language for eval

eval

scripting

should look into CLOS MOP, scheme macros (define-case -- what is it and why better than define-syntax?), ocaml (the "practical haskell"), self (small), io, javascript (prototypes), smalltalk (said to be beautiful), curry (haskell w/ logic programming), helium (simple haskell), Cayenne, SML modules (vs dependent types, or some restriction thereof?) (see also http://mlton.org/MLBasis). should read http://research.microsoft.com/en-us/um/people/simonpj/papers/history-of-haskell/index.htm. check clean, timber, other haskell derivitives. scala (and .NET) are said to support component programming.

modules? http://www.google.com/search?hl=en&client=iceweasel-a&rls=org.mozilla%3Aen-US%3Aunofficial&q=haskell+module+system+sml+power&aq=f&oq=&aqi=

  Cayenne wikipedia: "There is no special module system, because with dependent types records (products) are powerful enough to define modules."
  http://www.rubrication.net/2007/04/21/how-a-real-module-system-should-work/

ez FFI interface to libraries in interpreted languages, not just C interface

i think i like SML's modules, but would prefer for the compiler to construct the module defn for you. "internal" fns which don't go in the module are noted by the "hid" keyword (or just prefixed by "_", like in Python?)

ideally, the same syntax would be used for dealing with configure-time and run-time "components" and network "services" as for compile-time "classes" and "modules". REST-ful libraries, anyone? also must support WSGI layering

Cayenne dependent types look very useful and not hard to understand: http://en.wikipedia.org/wiki/Cayenne_%28programming_language%29

here's a good point about ambiguities in eq: "let/let rec problem is not a compiler optimization. It comes from people wanting to do two things with a similar syntax: let rec x = 0::x -- defines circular list let x = 0::x -- defines list of 0::(old contents of x) By comparison, in SML function definitions (fun f x = ...) have let rec and value definitions (let x = ...) have let semantics, and it's impossible to define circular values. So that's what you'd lose for getting rid of rec (unless you fixed the rest of the grammar at the same time).

" -- http://www.oreillynet.com/mac/blog/2006/03/haskell_vs_ocamlwhich_do_you_p.html#comment-27923

unicode

instead of "self", "me" is shorter (thx to http://en.wikipedia.org/wiki/Delegation_%28programming%29)

is comparison operator (not =)

"o" is composition

+= or maybe even a general mechanism for X=

imports throughout file as if in beginning

all names relative to module (NOT global) cyclic imports illegal?

syntactic sugar for - in front of a number to make it negative; i.e. -x is a single token that compiles to (negate(x)) (in jasper, you'd say (negate x))

nested comments

compiler: where is symbol X defined?

repr

for optional args? Lisp example from sds:

(with-open-file (f "foo" :direction :output) (write x :stream f :readable t :pretty t))

see prog const; allow any combo of (f x y) and (f(x,y)) and f x y syntaxes, and /f = infix f. div (or dv) = division

candidate two-letter reserved words when possible (then three letter); compiler expands(contracts):

sq (seq) cd (cond) if df (?) it (iterate?) lp (loop?) fl (foldl) fr (foldr) o (func composition) me (self object) ev (eval) dl (del) in (in, python set membership) pr (print) rpr (repr then print ; also a "rpr flag" that makes pr act like rpr) it (pronoun)??? x (pronoun) y (pronoun) z (pronoun) t (true) f (false) n (none/nil/null) i (position within a list)

slice [] graph [[]] graph, with subelements implicitly surrounded by [[]] () parens (()) castrate " strquote \ rightAssoc ' quote ` antiquote @ listExpand
&& and ; eol
or
  1. single-line comment /. ./ multi-line comment 1 list comprehension (2) $< >$ regexp ^< >^ eval (?) ^ unshadow ^x unshadow x (instead of xx) ^ ^ twice unshadow x (instead of xxx) & (in graph constructors): lexical node parent .: get, from the container typeclass. in graphs, this follows the edge specified by the key ..: graph labeled node accessor {}: type annotation. can follow a value, or can come just after a ( or [ or $[ or [[ that is surrounding/constructing the value. _ throw away ___ any token starting with ___

convention: tokens starting with _ are private to their module and its friends; with __ are protocols; with ___ are language, incld. language protocols

in []s: id (not identity!) self

mu (locally mutable variable) (but, better to just define as any l-value becomes locally mutable; i.e. x=3 x++ print x is like let x = 3 in x' = x + 1 print x' ) in that case... mu (globally mutable variable) (if multiple gl contexts, see "beg gl" below, then mu VAR CONTEXT sets non-default context (am i evil if i have a default gl context wrapping every program??) )

mb that mu should be "gl" instead, and reserve mu for object instance variables? or is that var (vr)?

mb (maybe (?))

mu: automatically infer mutable version of datastructures like hashes

python array slicing syntax; python list comprehesions

case insensitive (switch to turn off for compilation to other languages)

  1. for metaprogrammy thingees:
  2. number (even float!): footnote
  3. sub: replacement macro
  4. mac: macro
  5. inc: include
  6. beg ___
  7. end ___: begin and end sections to have something metaprogrammy done to them
  8. beg imp...#end imp: wrap contained fns with sq
  9. beg gl NAME...#end gl NAME wrap contained fns with state monad (semi-global variables)
  10. beg strict...#end strict all contained operations are strictified

metaprogrammy things cannot apply outside your file (module?), unless you give files containing them to the compiler/interpreter as special arguments

gotos that can target footnotes (within one fn?)?

cannot define new infix operators (use /), or new operator precedences; that power is something that makes haskell hard to read

i guess when there are multiple =s with the same lvalue that could be a sign that we want convenince mutation or mutable object setter, rather than function redefinition?

i guess that if we are in an imperative loop, then the mutable variable should persist through the different loop iterations, rather than being merely lexical sugar.


Perl has "there's more than one way to do it", Python "only one obvious way to do it". The former is motivated by natural language, and power, the latter by readability (and simplicity?). Perl has so many special syntaxes that if you don't learn all this stuff, you can't read other people's code. Haskell has a similar problem, but here it seems to stem from powerful hof libraries/typeclasses, and from things about its syntax (and basic libraries).

Jasper likes power and readability and simplicity; so "only one obvious way to do it" is good, but not to the extent that Python does it (Python's decision to not do tail-call optimization b/c we don't want people doing recursion, b/c there's already imperative iteration, seems too restrictive to me).


typeclass and class names start with capital letters

multiple inheritance

not a different namespace by type; altho object methods r in obj namespace (so mb it should be "%w[hi there].map(pr), instead of "map %w[hi there] pr". hmm, but this makes it hard to partially apply the pr to map). hmm, mb i take it back. fns live in module namespaces, not in objects.

each file is associated with exactly one module (by default, a new module is implicitly created for each file, but this doesn't have to be; you can put many files in one module). files in a module share a namespace, and you can do imports and metaprogrammy things in the module decl that will apply to all files in the module (but ea file can do its own imports and metaprogramming too, to allow for that quick test hack -- u are encouraged to move the stuff to the module decl later tho)


old (no infix functions anymore):

Infix functions

Some operators, for example +, are infix, which means:

You cannot define new infix functions (except by way of token operators, see below), but you can make any normal function that takes at least two arguments into an infix function by attaching '-'s to each side of it like this:

  2 -f- 3

arc: power, power, conciseness -- by macros and a drop of syntax python: readability, power, readability -- by syntax and standard idioms haskell: power, conciseness, safety/purity -- by static lazy purely functional semantics and MLish syntax perl: conciseness, power, naturalness -- by syntax

jasper: power, readability, conciseness -- by haskell semantics, syntax, and transformation of syntax for macros

cookbook comparison

. is "get" operator for containers and fields, not []: "list.3" is abbrev for "get list 3"

wrapper typeclasses: "for every type that is in the Num typeclass, it is now also in the boolean typeclass; we implement the boolean interface thus: "bool x = (x != 0)""

   note: haskell already does this: if JSON is a typeclass, u can write:

" instance (JSON a) => JSON [a] where toJValue = undefined fromJValue = undefined " ( http://book.realworldhaskell.org/read/using-typeclasses.html )

so now we don't have to do implicit typecasting, since all exposed functionality is in the typeclasses, anyway; we just keep track of the sets of types in each typeclass, and for each pair (type, typeclass), an "implication tree" that shows how that type was deduced to be in that class (i.e. what if types that were Num were wrapped into typeclass Q, and types that were both Num and Q(t) were wrapped into typeclass W, then the tree would show:

Num(t) (instance in file A) Num(t) -> Bool(t) (instance in file B) Num(t) -> Q(t) (instance in file C) Num(t) and Q(t) -> W(t) (instance in file D)

note: this is inference on Horn clauses, as each typeclass wrap declaration is a Horn clause

this tree tells the compiler how to actually do the various operations

but what if you add a new module and now it provides an alternate wrapper from Num to Q? Now there are two paths from Num to W. "Refuse the temptation to guess" and issue a warning that neither path has been chosen. If the W functionality is used, then issue a compilation error. The compiler should make it easy for the user (or their IDE) to find out how this happened; mb by default have a "compile log" that lets the compiler say, "btw, you used to use path Num->Bool (file B), Num->Q (file C), Num and Q -> W (file D), but then you added file E, which conflicts with file C for Num-Q. (or, at least, just point out that C and E conflict for Num->Q, which is what breaks the path to W).

haskell uses :: for types, we may as well use :. but how to indicate roles, properties, and keyword args? mb . with no prefix, i.e.:

f x .keyword1=y

but that's a waste b/c we have two extra chars . and =. mb just = with no space is sufficient?

f x keyword1=y

if u have optional todo

but if : is type, then what is list slicing? mb {} for type?

suggestion (following python http://docs.python.org/tutorial/controlflow.html#intermezzo-coding-style): 4-space indentation, and no tabs.

; for virtual EOL, {} for virtual EOL and indentation

what's the diff in the parse tree b/w {} and ()? nothing? then just use ()

some constructs (basically, those which in ruby take a block, or some which in Perl set $_, although that's also "it") introduce an implicit anonymous function definition around one of their arguments (the "block" argument) which binds x, or x and y, or x and y and z. so x,y,z are reserved words. example:

instead of [2*x for x in range(101) if x2 > 3], x is assumed, so

[2*x for range(101) if x2 > 3]

and instead of

search_engines = %w[Google Yahoo MSN].map do

engine
    "http://www." + engine.downcase + ".com"
  end

in ruby, or the eqiv with my syntax and {}s,

map (fn engine {"http://www." + engine.downcase + ".com"}) [Google Yahoo MSN]

or the equiv with my syntax and ()s,

map (fn engine ("http://www." + engine.downcase + ".com")) [Google Yahoo MSN]

the "fn engine" becomes an implicit "fn x", so

map ("http://www." + x.downcase + ".com") [Google Yahoo MSN]

how to write this in the fn defn?

so far we have 3 semantics for =s, depending on context.

if not surrounded by spaces, left-hand-side is a property and right hand side is a value: property=value

if surrounded by spaces and the lhs is of the form ().() (or x.y, or x.(), or ().y), then it x.y = z is short for "set x y z" (and if u r setting a non-mutable object, the set will return the new obj, in which case it is lexically bound as a convenience variable update to x)

if surrounded by spaces and the lhs is otherwise, then it is a fn defn, i.e. "f x y = x*y" is short for "defn f = fn (x y) (x*y)" (if "defn" even exists.. = lisp's "setf"? anyway, = basically will be used for defn or setf, so this use of =s is actually atomic, mb...)

  1. char unicode charset encoding (must be at top of file)
  2. jver jasper version
  3. ver module version

mb should use # for comments, like in ruby, and find another character for metaprogrammy, like mb %

nested, (possibly) multiline comment syntax w/o chording: how about /. to open, ./ to close

use properties on typeclasses to help the compiler pick the default type; to say that you want a container implementation with fast lookup (like an array or dict):

x{contain lookup=fast}

looks like haskell doesn't even have (user-definable) defaults:

http://hackage.haskell.org/trac/haskell-prime/wiki/Defaulting

docstrings and properties on fns (is this like javabeans?):

"""f does something cool""" functionColor=red, temp=cool f x y

of course, properties and docstrings can be reflectively accessed at runtime (although, perhaps not changed??). but mb their main use is at compile time, for IDEs and macros.

%% means "execute this at compile time". if this is line oriented, we should have an open/closer (%/, /%)?

str fns, literals take unicode. to deal with bytes, use bytestr, encode, decode

attributes: .. operator. takes an object on the left and a string on the right -- the value of the string is an "attribute name". can set using = (as with . and "get", maps to "getAttr" instead), or can get just by "..". each attribute may be a different type. by default, getAttr and setAttr call a generic routine that just stores the value, but instead u can use "handleAttr obj attrName get &set &remove" to tell getAttr and setAttr to call your functions for a specific attribute. behind the scenes, each object is actually a subclass of what u think it is, with a typed struct which is used by the generic attribute accessors to store attribute values. the "add" fn is used to add an attribute value "dynamically" (although actually this subclasses and adds statically behind the scenes). "add" only takes constant strings, to ensure that we can set the attribute field types at compile time. ????

	   mb should just use graphs, see below

mb attr lookup should be symbol by default, not string, since we're making everything all static anyways. have a string conversion option like python does.

objects like "2" and "5" can be objects, but "final" objects, meaning they're singletons and u can't change their attributes (perphaps "final" is a pseudo-function that u run on them when ur done setting them up)

typeclasses ("classes") should be encouraged to have default instances. if they don't, mb should be declared (or at least labeled by the compiler) as "abstract".

default, keyword, and unlimited positional argument handling, as well as list and dict unpacking, as in python: http://docs.python.org/tutorial/controlflow.html#more-on-defining-functions

don't need rfn like in arc ( http://www.paulgraham.com/arcll1.html ) b/c haskell's fn defn can be used directly within fn scope

xx, yy, xxx, yyy, zz, zzz can be used to refer to the enclosing scope's x, y, xx, etc when they were implicitly bound actually, use ^x, etc

mb allow macros to un-hygenically refer to x,y,z,xx,etc,it, via ^x, ^j, etc

mb / instead of --. / is tall and asymmetric. find something else for infixing

@x means "insert the contents of list x right here"

note: i'm trying to make the most common punctuation unchorded

notation for "rooted" graphs (such that an edge can point to another edge; perhaps like the "homogeneous viewpoint" in category theory, or topic graphs):

[] surrounds root node (surrounding []s can be omitted when ,s are present inside) (can be implicitly closed by indentation) [[]] like [], but subelements implicitly surrounded by [[]], and spaces separate (except for things right next to =s) ,s separate elements elements are nodes that parent node points to "label = node" is notation for local edge labels (don't have to be unique) "node ^^ id" is notation to reify an edge and give the corresponding node id "id" [id

reserved labels: id, n ("n" is implicit label for unlabeled edges) (mb "v" would be better, for "value"???) comparison operator ^= means "do the lhs and the rhs point at the same node in the same graph" $[] means that tokens will be interpreted as strings, not variable names, except for tokens prefixed by ` ; also, like [[]], u can separate by spaces within a graph construction, "self" as a value refers to the current node, as if it were a node id & is the "parent" operator. & self refers to the (lexical) parent node (since this is a graph, nodes may have multiple actual parents) & & self refers to the grandparent within a nested rooted graph construction, "root" as a node id refers to the root within a graph construction, the graph's nodes' ids are bound to symbols, i.e. if some node is called "bobsNode" within the constructor "thisGraph = [ ..." then "bobsNode" is short for thisGraph.bobsNode. if this shadows some other symbol named bobsNode, use the unshadow operator ("^") to get that one: ^bobsNode edges can have multiple labels, denoted by a list: [[label1, label2] = value] (or, if u prefer, [(label1, label2) = value]) unless the type is tagged "singleLabel" to add a label to an edge later, use fn addLabel or somesuch each edge is implicitly also labeled by its position within the edge list (which may be changed later) unless the type is tagged "unordered" multiple edges cannot share the same label unless the type is tagged "nonuniqLabel" this is b/c ow the "get" operator's return type must depend on whether the requested edge is unique in each particular case, b/c it usually returns the value itself, but if there are multiple values, it should return all of them in a list.
value1, value2, etc] is notation for a root node with a node id (global label) "id"

note: local node labels not needed; global edge labels provided by reified edge nodes

example: a single node with value "10": ex = [10] ex.n == 10

example: a single node that points to itself: ex = [s

ex = [self] ex.n ^= ex
s]

example: a list

ex = ["apple","banana","cherry"] ex = [["apple" "banana" "cherry"]] ex = $[apple banana cherry] fruit2 = "banana"; ex = $[apple `fruit2 cherry] fruit23 = $[banana cherry]; ex = $[apple `@fruit23] ex = "apple", "banana", "cherry" ex.0 == "apple" ex.1:2 = ["banana" "cherry"] ex2 = ["grapefruit", @ex] ex2 = ["grapefruit","apple","banana","cherry"]

example: an association table ex = [[ apple = red banana = yellow cherry = red ex = assoc $[[apple red] [banana yellow] [cherry red]] ex = assoc $[apple red], $[banana yellow], $[cherry red] ex = assoc $[ apple red banana yellow cherry red ex = assoc [ "apple", "red" "banana", "yellow" "cherry", "red" ex = assoc [[ "apple" "red" "banana" "yellow" "cherry" "red"

/. note: assoc takes a list of nodes of form [key value] creates one node whose labels are the keys and where the associated values are the values ./

/. note: if you wanted some 1-ary function "f" instead of 0-ary "apple" inside [[]], you'd put it in double parens to "castrate" it: [ ((f)) "red" ...

./

/. mb no commas OR []s are even needed when things are 0-ary?

"apple" "banana"

naw, too hard to read if u don't know the arities. use [[]] if u want spaces. ./

ex."apple" == "red" 3 == $[red yellow red] vs ex == $[red yellow red] ids ex == $[apple banana cherry]

ex: a state machine ex = [[ appleState

transitions = ["0" = self, "a" = self, "c" = cherryState], color = "red"
        bananaState | transitions = ["a" = appleState], color = "yellow"
	cherryState | transitions = ["0" = self, "a" = appleState], color = "red"

ex = [[ appleState

transitions = ["0" = self "a" = self "c" = cherryState] color = "red"
        bananaState | transitions = ["a" = appleState] color = "yellow"
	cherryState | transitions = ["0" = self "a" = appleState] color = "red"

ex = [[ appleState

transitions =
	    "0" = self "a" = self "c" = cherryState
	  color = "red"
        bananaState | transitions =
	    "a" = appleState
	  color = "yellow"
	cherryState | transitions =
 	    "0" = self "a" = appleState
	  color = "red"

ex = [[ appleState

	    transitions =
	        "0" = self "a" = self "c" = cherryState
	    color = "red"
        bananaState |
	    transitions =
	        "a" = appleState
	    color = "yellow"
	cherryState |
	    transitions =
 	        "0" = self "a" = appleState
	    color = "red"

ex.1 =^ ex..appleState # mb should allow graph types to be tagged "unordered", tho ex..bananaState.transitions."a" =^ ex..appleState ex..bananaState.transitions."a".transitions.

example: a sparse 2D matrix:

ex = {mut} sparsearr 0 1000 1000 /. sparsearr takes a filler element and an arbitrary number of dimensions; the "mut" type tag means mutable ex.566.221 = 1 ex.200.200 == 0 ex.(565+1).221 == 1

/. note: . is just the container get. this is equiv to: ". (. ex (565+1)) 221". the sparsearr doesn't actually have to store this as a vector of vectors; it can have a fn get2D which takes a container and 2 address arguments, and say ". arr x = get2D ex x", and ". (get2D arr x) y = get2D arr x y" (well, mb it would have to wrap (get2D arr x) in some dummy type) i.e. it maps to a partially applied get2D. then ". (. arr x) y = . (get2D ex x) y = get2D arr x y". the compiler could notice (or be told) that these substitutions are indep of the addresses, and replace "ex.(565+1).221" with "get2D arr x y" at compile time. Alternately, since this is sure to be a common pattern, a special . fn defn syntax could be provided, i.e.:

. . obj x y = ...(something similar to the body of get2D arr x y

./

/. node labels are implemented by adding a "supernode" for each graph whose edge labels are the graphs node labels, and whose edges point to the corresponding nodes. so graph.. is just . on the graph's supernode (as opposed to graph., which is on the root node). attributes can be added to non-graph objects by treating them as graphs with a non-graph root node (i.e. abstractly, there is really not a root node, just a root edge, and "obj" follows that edge -- if obj is a graph, it points to the root node of the graph), but they can still have a supernode. the node labels (which are identified with the supernode's labeled edges) are the object's attributes. this way, attribute reference is a special case of graph operations, and node labels are a special case of edge labels. ./

graph schemas?

todo: graph types

to castrate a fn, @[f]. perhaps a shortcut is in order.

partially applied infix is allowed, but don't call it "sections" like in haskell

i take it back, "," isn't for implicit []s. it is just a grouping operator.

main grouping ops: () a b = ((a) b) , a,b = (a) (b) / a / b = a (b)

.. doesn't make sense: how is , diff from left assoc... it does differ: a b c = ((a) b) c, but a , b c = ((a) ((b) c)

a b c d = ((a b) c) d a b , c d = (a b) (c d) a b / c d = (a b) (c d)

so , is same as / (?)

so mb go back to [] implied by ,s?


pattern matching: one thing that makes pattern matching good is that it in effect lets you do the partial inverse of a constructor, ("partial" meaning with regard to a particular argument), without learning the name of another function. so, for example, if you do

  x = cons "a" []

which in haskell is x = "a":[]

then you can pattern match like:

  f "a":rest = blah

which is similar to the conditional (in Python syntax)

  if (head x) == "a":

so, since by definition head(cons x y) = x (that's what i mean by partial inverse), the pattern matching syntax lets you just reuse the "cons" operator rather than referring to the "head" operator. this makes things easier to remember/read, and is more elegant.

now, how to do pattern matching with opaque types, with only a typeclass interface? the interface defines one or more graph structure that can be given to a constructor, and also queried later in a pattern match. for example, if the object is in the list typeclass, then you can do

  x = obj $[a b c]

to construct it, and

  f [a _ _] = blah

to match it. but since multiple constructors can be provided, you can also do x = cons "a" [] {obj}

  f cons "a" rest = blah

and you can mix and match, i.e.

  x = obj $[a b c]
  f cons "a" rest = blah

(also, mb introduce the ... operator so that you can match on ["a" ...]; or mb use ["a" @rest]?)

the convention is that if the object is equivalent to one constructed by

   constructorN x y z

then any pattern consistent with constructorN x y z matches it

patterns can be nested, i.e.

   cons ["apple" = x, @rest2] @rest1

which means, match on any list (actually, graph node) whose first element is a dict (actually, graph node) which contains an entry with key "apple". if it matches, the value mapped to by "apple" will be bound to symbol x.

in other words, each constructor in the interface must implement both a function to construct, as well as the pattern matching (if u don't want to implement the pattern matching, that's fine, it's just a fn, not a constructor). the pattern match can be a function, or it can be phrased in terms of another pattern match using a graph transformation. For example, if you have a list implementation type which internally stores $[a b c] as [a=1, c=3, b=2] for whatever reason, then to match pattern pat=$[a b c], you'd do something like

  lmap (v=i) pat
  pat.__ordered_labeled_nodes = f  # doesn't need to be included, as it's the default

patterns are just graphs whose values can be symbols, including the throw away symbol _. nodes with edge labels match other nodes with the same edge label regardless of their positional order within the parent node unless the parent node has __ordered_labeled_nodes.

lmap is "list map", it maps only over the top level elements of the graph (mb should be tmap, for top? b/c it is also useful for tables). it is a specialization of "map", which by default maps over all elements of

     how to distinguish "edges"? should be "two steps down", like [] in syntax tree.. no, b/c then a list of lists that happens to have a single list in it would be confused with an edge. need a second reify operator, not like ' which reifies through the context of symbol evaluation, but something that reifies within the context of the boudaries of a data structure.

mb [x] should mean "reify (x)", rather than be the graph constructor. mb a graph within a graph should be "[fruits=("apple", "pear"), vegetables=("carrot", "brocoli")]", and a tree with leaves should be:

    [root | (branch 1 | (branch2 | ["leafAtLvl3"]), ["leafAtLvl2"]), ["leafAtLvl1"]]

which is equal to

  reify
      root |
          branch 1 |
              branch2 | reify "leafAtLvl3"
              reify "leafAtLvl2"
          reify "leafAtLvl1"

mb if the members are not themselves graphs, but some other type, the reification is implied, so the following is equivalent:

  [root | (branch 1 | (branch2 | "leafAtLvl3"), "leafAtLvl2"), "leafAtLvl1"]

if the leafAtLvlNs were just symbols that might themselves hold graphs, though, then you gotta reify:

  [root | (branch 1 | (branch2 | [leafAtLvl3]), [leafAtLvl2]), [leafAtLvl1]]

without the node labels, this graph is:

  [(([leafAtLvl3]), [leafAtLvl2]), [leafAtLvl1]]

or

  [
              [leafAtLvl3]
          [leafAtLvl2]
    [leafAtLvl1]
  ]

so now the comma means "brother nodes; don't try to left or right associate". but now we can't do all function applications within graph constructors: f x y z is fine, but f (x y) z isn't -- wait a minnit, that's not ambiguous... hmmm.. it depends on if there are spaces outside the parens, huh.... cool...

note: a tree with more than one level of reification is best rendered in 3D :)

so mb in core jasper, the roots of function applications are an "apply" symbol?

so multiple assignment can be generalized to graph assignment, (only recursing up to reification? or only recursing up to symbols in the assignment?). so,

  a,b = 1,2

is like

  a = 1
  b = 2

and

  a,(b,(c)) = 1,((2,3),(4))

is like

  a=1
  b=(2,3)
  c=4

but if c is an object, we can put things in its "members" (i.e. named edges), e.g. if "student" has a writable list "classes", we can call "set" on it implicitly:

  a,(b{student}.classes,(c)) = 1,(("cs101"),(4))

is like

  b = student
  a = 1
  set b 'classes ("cs101")
  c = 4

(although mb the order of these calls should be different -- or mb it should be undefined)

the reason this is useful is that fns can return graphs:

  f "fred" = $[Fred sophomore (cs101)]
  s = student
  s.name, s.year, s.classes = f fred
 in fact, on second thought, graph assignment is just like fn argument binding, so unbound rhs edge labels don't bind positionally. when the lhs graph has an edge label that matches an rhs edge label, assignment binds edges to matching edges regardless of order, and further unlabeled rhs edges are an error, just like with keywords in fn application (in python, "SyntaxError: non-keyword arg after keyword arg"). furthermore, defaults are allowed on the lhs, but in a given node, arguments without defaults can't follow defaults (in python, error "SyntaxError: non-default argument follows default argument").:
  s1 = student
  s1.name, s1.year, s1.classes = f fred
  s2 = student
  s2.name, s2.classes = s1

instead of, like python, allowing any symbol to bind to the leftover keyword and positional args, predefine special edge label names (mb. "more"). should we even allow leftover positional? can't people just pass lists in the usual arguments? let's ban leftover positional.

note that since object classes define a bunch of members, mb we could just specify the class and let its graph be the lhs, although obj member fields should be unordered, i.e. can't accept positional args:

  x = [name = n, year = n, classes = n]
  x.name, x.year, x.classes = f fred
  s2 = student
  s2 = x
  /. since x has edges "name", "year", "class", this is mb like
       set s2 'name x.name
       set s2 'year x.year
       set s2 'classes x.classes
  ./

but i don't like that, b/c as i said above, how do u kno when to stop recursing into s2? better: keep the convention that symbols in the lhs are the binding point by default, and use @s2 to indicate the other case (and with @s2, stop recursing at reification boundary, i.e. the leaves). to only insert the top layer of a graph, use @(top s2), where top G = layer 0 G, and layer n G means insert reification below the n+1th layer.

but then @ can't mean syntax level-up. hmm.. ok, yes it can. "a = [1, 2]" doesn't actually store a list with a terminator (my new name for the [] reification operator) on top at symbol a, it just stores 1,2, the root node of that graph. so @g does mean replace (syntactically) with the contents of g, down to the terminator, and "a = [1, 2]; b = [@a, 3]" yields b = [1,2,3].

mb when the type of x is code, rather than a graph, @x can mean eval.

still need a convenient syntax for regexps and friends. something involving % would be nice, but is inconvenient. mb x ? so r for regexps. users can define others, with different string prefixes replacing the r. /, , /+ are reserved for future use. %/ are things that are parsed, from string, at compile time. also need a syntax for things that are parsed but then passed to a macro.

mb instead of shifted % meta prefix, that should be for meta definition, whereas meta usage is , /, etc. so: x( ) surrounds meta things that are parsed. x/( )/ surrounds things that are not parsed

there should be a fn that takes as input a list and a lookup table, and yields as output a list of equal length which is the translation of each item through the assoc table. this can be combined with treemaps to translate leaves in a tree. i guess the cleanest way is a "tl" fn which takes a table and returns a fn that translates according to the table. 3 variants that deal with items not in the table differently: raise an error, use a default, pass thru the input item unchanged.

in fn args, auto escape incoming ns if the default is n. better: special syntax to identify "no argument passed". "$@color" evaluates to a bool that is t iff a non-default arg was passed in arg "color".

even when using pronouns, need to distingush a fn block in parens from an expression returining a fn. use $$() in code as shortcut for () z=n x=n y=n i=n j=n fn.

how helpful is this? for one var, not too much: $[apple banana] (("http://" + x + ".com") x fn) map $[apple banana] $$("http://" + x + ".com") map

"it" is set in a block by a function it calls, i.e. in inner scope reaches out and sets it, as if all fns that look like they say y = x f actually say [y,it] = x it f, and if f is annotated so as to do so, it sets it. by convention (and mb enforced by compiler via garbage collection), it should only be set to something that you are returning anyway.

"e" is set to the success or failure code of the previous fn.... no, wait, what am i talking about, only use exceptions. mb e is bound to the exception in the exception handler.

x.y.z = 3 -> x.y.z = set x.y.z 3 or, more generally, b/c, say, y might be bound to an object which turns z into a method; depending on where the object starts, we may get something like: -> x.y = (setCall x.y .z 3) hmmm, this seems a bit too dynamic, requiring runtime evaluation of stuff; can we decide at compile time? yes, if the boundries of objects are decidable at compile time so, when set is called on a method in an object, the whole object is mutated, not just that method

  however, this is still different from a non-functional (non-referentially transparent) language; the only thing that can be mutated here is subparts of the lhs of the equal sign; in python, if you do 
    x = [1]
    a1 = x
    x(1) = 2
    a2 = x
  then you will have a1(1) = 2; in jasper a1(1) would remain 1.

mb ! is syntactic sugar for "mutation", i.e.

x.y.z.sort! -> x.y.z = x.y.z.sort x.y.z

(with the same caveat as above about object boundaries; if x.y is an obj that defines x.y.z.sort, then

x.y.z.sort! -> x.y = x.y.z.sort x.y

)

oops, the syntax in the last few examples is wrong. x.y.z.sort means, start with the root node of x, follow the edge whose label is given by the value of variable "y", follow the edge whose label is given by the value of variable "z", follow the edge whose label is given by the value of variable "sort". to invoke a sort method. also i forgot the backwardsness.

x.y.z sort

so

x.y.z sort! -> x.y.z = x.y.z sort

or, if y is an object,

x.y.z sort! -> x.y = x.y sort

which can be simply seen by undoing the syntactic sugar and looking at . as "__get" function in normal usage, or as a selector for __set when on the lhs of an =s:

x.y.z sort! -> x.y.z = z (y x __get) __get / sort ->

  1. wrong, need selector: (z (y x __get) __get / sort) (z (y x __get) __get) set (z (y x __get) __get / sort) (z (y x __select) __select) set

why do we use a selector in __set, instead of just nesting it, like with __get? imagine a 2D array, which is presented as an array of arrays, but which is actually stored as a single array. let's say that the underlying array access is via fns "y x arr get2Darr" and "v y x arr set2Darr". accessing row 2, column 3 would be by a.2.3, which translates to

  3 (2 a __get) __get
 this is fine, b/c "2 a __get" can refer to an object B that stores a partially bound get2Darr, "2 a get2Darr", and we can set it up so that "3 B __get" should bind 3 to the remaining slot in the stored get2Darr (todo: convenient syntax 4 this). but the analogous strategy for a.2.3 = 4 would be to do

4 3 (2 a __get) __set

hmm, one second thought, that doesn't sound so bad. so

x.y.z = a

is short for

a z (y x __get) __set

hmmm but as an object, it gets private instance vars, right? but then it could violate intra-object referential transparency by changing the value associated with x.y.2 when x.y.3 was changed. but we do want to allow objects to have instance vars; for example, what if the object is caching parts of some expensive lookup operation, e.g. if x.y.[2 3] might require doing some expensive computation on 2, and then some expensive computation on 3, and then some quick combination of the result; and mb we want to assume that the caller will ask for lists with the same subparts over and over, so we want to cache the results; so looking up x.y.[2 3] does change our state, so that we can be faster when we look up x.y.[2 4]. mb a simpler example is a lookup table which is internally stored as a tree, where the tree is periodically rebalanced as items are added.

so, the convention (law) is that objects are responsible for maintaining referential transparency intra-object. so x.y.[2 4] has to always return the same result, whether or not we have previously looked up x.y.[2 3], even if covertly, it computes it a different way. the compiler/runtime is allowed to cache the return value, omit unused calls, etc, so it won't work if ppl break ref trans.

is this sort of optimization even worth the risk of breaking ref trans? i dunno, probably not for most user-level stuff, but we want to be able to implement lookup tables as balanced trees etc --- the point is to be able to use the nice uniform graph syntax for as much as possible.

there could be a notation for defn of "laws" as asserts that the compiler can run when in debug mode (i.e. before/after each relevant operation is run on an object, the compiler does the law checks). actually, this could be part of a more general facility, using type tags and preprocessor directives (compiler modes?), to allow objects to export optional error-checking levels (i.e. do we want this array to bounds-check upon each array access event?). also, the compiler could support the IDE by providing a list of laws applicable to any symbol upon demand.


  1. is EOL comment so we need something else for footnotes footnotes could be named (one word), not numbered

should we require mutable variables (true references) to have & token prefix, rather than mut decl? this is more readable but less writable. i guess i just answered my own question -- yes. actually, mb use * prefix to agree with C.

representations: x.y&assoc.z

selector representation (reification): &x.y.z (default rep) &x.y&assoc.z

selectors are basically paths in the graph. the difference is that when a selector is passed to an object, that object is only given the portion of the selector that goes beneath it. that's a little vague b/c functions take arguments, not objects. so, for example, if y supports the I interface, and f is an I interface function, then

  &x.y.z f

would only pass &z to f. if x.y supported I, and within this, x.y.z also supported I, then

  &x.y.z.w f

would pass &z.w to f; but f might choose to pass it onto z, which would see it as &w

clarify that graph pointing is (ref trans) copying. change to label overwrite. guarantee that if u throw away the first variable, no copy is actually done. idiomatic way to do this is convenience mutation, i.e. x = ["a"

["b"2], 3]; x = ["c"x.."b"]. note: b/c of convenience mutation, if u WANT recursive symbol binding, must use special syntax, "x = $rec$(x)"

"trash" to tell the compiler that it should delete a variable now. presumably either nothing will happen or it will complain :) this is mainly useful for debugging memory and for readability

facility to define a class as an enumeration of some finite subset of objects of another class. this way, members of an enum can be used as the type of edge labels for something, and so even if the edge is chosen dynamically, the compiler can be statically sure that the edge will fit (that sounds unnecessary -- what was the real use case, i forgot it?). ok, i think i got it, that was almost it. the idea is that, there might be various edges of different types, for example a resizable array of ints might also have an edge that is a "name" attribute or something, that holds a string, and also a "length", that holds an int, and a "capacity", that also holds an int. you want to have another variable of type "int" to which can be assigned either the length or the capacity, and you want to choose which one dynamically by passing in one of those two labels to a subroutine. in order for this to typecheck, the compiler needs to know that you might pass in either of the strings "length" or "capacity", but you definitely won't pass in "name".

note that, since we have disjoint types, you can also make a type that is either "length" or "capacity" or an integer, but not a name.

if arbitrary slices of numbers are allowed, then we can use this to implement typable bounds-checking too (in very simple cases when you can prove to the compiler that you don't exceed the bounds -- for example, it would often work for int variables to actually have the type "natural number"). but since the compiler isn't going to be proving arithmetic theorems for you, that sounds like a lot of pain for not much gain, so let's not bother.

some keyword arguments should have positional locations within nodes, but some should not. you don't want element 5 of your 3 element array being "length" or whatever. also, you'll often want all the positional args to have the same type. mb "--" divider or something; or mb or

.

rationale for making the default midx the one that throws an error.

the three obvious choices are midx, midxrn, and midxic.

midxrn is "the right thing to do" but it's a pain b/c you have to make use of the renaming tables. If you use midxrn but ignore the renaming tables, it's like using midxic, except that you'll have even more situations with silent misbehavior.

Now, either you are lazy, or you want to do things right and know about midxrn, or you want to do things right but forget about midxrn.

If you're lazy, and midxrn were the default, you're not going to use midxrn's renaming tables properly anyway, so if there is a problem there will be silent, sporadic failures. Silent, sporadic failures can be really hard to debug; if you start off lazy but end up using the program more seriously than you planned, you're in trouble. So this could be a big problem.

If you want to do things right and you know how to, you will use midxrn in any case, regardless of the default.

If you want to do things right but you forget to use midxrn, you will at least get an easily debuggable error when the problem hits if you used midx. It would have been better for you if midxrn had been the default, but at least it's not a silent failure.


if u have ad-hoc polymorphism via multiparameter typeclasses (interfaces), do you even need parametric polymorphism? it would be nice if u could do away with parameterized type constructors (since u already have parameterized interface constructors)


old:

three use cases:

1) (scripting for self) you are writing a quick-and dirty script or a prototype, one that probably will only be run a few times, and in which misbehavior is not that important. You want to write it quickly. 2) (careful scripting for self) you are writing a quick-and dirty script or a prototype, one that probably will only be run a few times, and in which crashing with an error is not that important, but you don't want it to silently misbehave. You want to write it quickly. 3) (for others to use) you don't want errors or crashes. you don't want it to silently misbehave. you want to be able to debug it easily. You don't mind if it takes awhile to write, you just want it to work.

the best for #1 is probably midxic; it's easy to use, and if there are clashes, this might resolve them the way you want; but if you're unlucky, it'll silently misbehave. the best for #2 is probably midx; it's easy to use, and if there are clashes, it'll tell you. the best for #3 is probably midxrn; if you make use of the renaming tables it provides, it'll work.

if we're in situation #2 or #3 and we use midxic, we have some cases in which there are silent misbehavior, which may be sporadic and hard to debug. In situation #2 we are annoyed and in #3 we are extremely annoyed.

if we're in situation #1 and we use midx, we have some cases in which there are crashes, and either we have to go change it to midxic (in which case we're slightly annoyed that the default wasn't midxic), or we have to do something more complicated (in which case we would have had to anyway). if we're in situation #3 and we use midx, we crash in some cases, and we have to switch to midxrn, in which case we're annoyed that the default wasn't midxrn, which would have reminded us think about the label clashes earlier.

if we're in situation #1 or #2 and we use midxrn, we are too lazy to do anything with the rename tables, so we just ignore them, causing silent misbehavior sometimes. In #1, we would have been no worse off using midx, which wouldn't have worked either, and in #2, we would have preferred midx.

we have some cases in which there are crashes, and either we have to go change it to midxic (in which case we're slightly annoyed that the default wasn't midxic), or we have to do something more complicated (in which case we would have had to anyway). if we're in situation #3 and we use midx, we crash in some cases, and we have to switch to midxrn, in which case we're annoyed that the default wasn't midxrn, which would have reminded us think about the label clashes earlier.


(some thoughts while reading gentle intro to haskell (i already know haskell, at least at that level):

in haskell, u can have

  data Point a = Point a a

in jasper, types and other things live in the same namespace, so u can't (tho mb interfaces must be capped)

in haskell, if

  data Point a            = Pt a a

then

  Pt 'a' 1
 is "ill-typed". in jasper, probably this is typed with a disjunctive type.(the lattice join, or is it meet? if types are subsets of all possible values and subset inclusion is the operation, the disjunctive types are unions which are joins)

in haskell, u would have

  data Tree a             = Leaf a | Branch (Tree a) (Tree a) 

in jasper, prob Leaf and Branch would be separate types, and Tree would be a disjunctive type (tho also in this particular example, in jasper, we already have primitive graphs so there's less use for a generic tree type)


C++ already has pointers. what does jasper's graphs offer C++?

well, C doesn't have concise syntax for manipulating arbitrary-sized lists of arbitrary objects, and it totally lacks a concise syntax for built-in tables

  what do jasper's graphs offer python?

a single data structure that unifies lists, dicts, and other things like trees.

other relative advs:

vs C++: concise syntax, type inference, easier hof vs Python: static typing, easier hof


type tags: use the type that satisfies the tags on the left, going right as far as possible. eq classes? if tie, the implmentations have a way of specifying "i'm better than him" or "he's better than me". believe all these, and do a topo sort. start with the default type implementation given in the class defn, if any.


can unify functions and objects by having a __call method protocol (i.e. edge label) that means "if this object is called like a function, then here is what to do". now the . operator, except when on the lhs of an =, just means function call. e.g.

x.y is the same as y x. note the additional "benefit" of . serving as a syntax for left-associative function application.

when an object is on the lhs of an =, we call __set at some point instead of __get. (2 options that i still haven't decided b/t: pass the top object a selector (path), or just call __get (which is now __call) until the second to last edge, at which point we call __set instead; i'm leaning towards the latter)

now, we need a way to say that some symbol is a member of some class; after all, when __call is used to figure out what to do when some object is called like a function, it's the class's __call edge, not the object's, that is followed (of course, the class can itself be called b/c this is how we __get its edges, but the __call edge there will be in the metaclass) -- unless we use a prototype object system, hmmm, interesting.

but this is similar to saying that it is in typeclass. so, we have unified typeclasses and objects -- a typeclass is a class object.

so mb what we are making here is like a lazy, functional, statically typed smalltalk or self with loads of syntactic sugar including syntactic support for partial function application. i need to look into those more.

so this makes the static typing system one of the more important differences. and the key there is that we are unifying typing and pattern matching, and using a graph typing system, and mb the flexibility of disjunctive types is important too.

remember that need to make it so that interfaces, and mb even implementations of interfaces, live in modules, not global

a reason for cycles in g-constrs is that we want to model recursive fn defn in code

the node label namespace in a g constr can actually be the global namespace in code g-constr (hmm, lexical?!)

as syntactic sugar, symbols in function calls can be automatically converted to symbols imported from the callees module (i.e. in "apple = module2.Fruit; apple.'color = "red"" 'color should be converted to "module2.color". mb "thisModule" reserved word?)

multiple dispatch ("multimethods"), that is, same name but diff signature?? sounds useful for constructors...

if __get is just function apply, then x.y.z is just ((x) y) z (remember we are backwards), that is, . is just a tight-binding ("short scope") left-associative grouping separator

two other merge methods:


3/4/*

map.*

3-4-*

3_4_map

refl obj (or "me")

add self loops in graph -- pass to fn, trans to self

specialization: [2 a b] -/* (or just /* ?)

autolist: 2 a b -/* (or just w/ -/ ?)

componentwise

no infix?

3_4_* best, but unneeded if cheap syntactic foldr, b/c (3 4 *) is just as ez to write, so only benefit would be assoc, which isn't there anyway i.e. 3*4*5*6 vs ((3_4_*)_5_*)_6_*. also, main benefit of 3*4 is only 3 chars b/c no spaces, impossible to acheive for arbitrary alphabetically named fns

w/ cheap syntactic foldr,

(-b + sqrt(b*b - 4*a*c)) / (2*a) vs

b b * , 4 a c , - sqrt b - , + (2 a *) div

(more fair comparison, minimal arbitrary incld. spaces vs. no unnec spaces, double slashes:) (- b + sqrt(b * b - 4 * a *c))/(2 * a) (b b *,4 a c ,-)sqrt/b -,+/(2 a *)div

minimal arbitrary incld. spaces vs. smallest readable (- b + sqrt(b * b - 4 * a *c))/(2 * a) (b b *, 4 a c , -)sqrt/ b -, +/ (2 a *)div

now w/o /:

(- b + sqrt(b * b - 4 * a *c))/(2 * a) ((b b *, 4 a c , -)sqrt, b -, +) (2 a *)div

(most readable of mine:

((b b *, 4 a c , -)sqrt, b -, + (2 a *) div

vs. w/o

((b b *, (4 a *) c *, -)sqrt, b -, + (2 a *) div

)

so * prefix means 'args as list'. mb / prefix means foldr, so */* is mult. naw.. we don't need to choose b/t foldr and foldl (or foldr') for syntactic fold, b/c small list. choose foldr for readability. how about just *? actually ea. fn must define so that they can define the initial accumulator value.

so,

1 2 3 4 *+ == 10 1 2 3 4 == 24 1 2 3 4 *- == (1 (2 (3 4 -) -) -) = -2



decided not to do this (instead, default args must be keyword only, not positional):

An exception to this equivalence (and to right-associativity) is that if the function as written takes k arguments, but it returns a function, then you are not allowed to write it with more than k arguments directly to its left; the extra arguments must be separated from the "real" arguments by a '(' or or a ',' or a '.'. So, for example, if f is a function that takes two arguments, which are themselves function, and returns g, which is a function that takes two arguments, then according to right-associativity you would be able to write:

 1 2 x y f

but in Jasper this causes an error, and you have to write instead

 1 2 (x y f)

The reason for this restriction is to enhance readability; because Jasper supports default arguments, readers will sometimes see the same function being called with different numbers of arguments, and yet we want to make it easy for the reader to distinguish the set of direct arguments from the set of arguments being provided to the function that was returned. Even without this restriction this would be possible (by looking up the function definition and seeing the maximum number of arguments possible) but it would not be as easy (you could not just look at other code that uses the function, because maybe they are leaving out some default arguments).

(potential prob: disallows point-free notation, i.e. can't say

  f = *
  2 3 f

b/c then f in 0-ary "as written". Do we care (yes)? What is the most readable fix?

)

An exception to the restriction is when a 0-ary function returns another function; in this case no grouping is needed.


decided not to do this:

 If an argument is given as a keyword, then no positional arguments at positions greater than or equal to that argument's position may be given at that time (although if the result of the function application is assigned to a variable or put in parentheses, then that variable or subexpression can accept positional arguments, which will fill the remaining "empty slots" in order)

ok, i'm going to cut and paste and summarize for a bit.

the jasper programming language

Why Jasper? -- built around a powerful data structure: labeled graphs -- referential transparency -- readable, concise syntax -- memory managed. static typing, type inference. lazy evaluation. higher order functions. -- goal: the referential transparency, higher order functions, and type system of Haskell, the readability and convenience of Python

audience: general purpose. programmers.

statically typed. memory managed. type inference. lazy evaluation. higher order functions.

support for the following paradigms: imperative, oop, functional (referential transparency), logic, macros

priorities: power, readability, conciseness

syntax that compiles to cleaner core

primary data structure(s): labeled (reifiable) graph. this also provides a syntax for lists, association tables, arrays, trees, graphs, relations, structs, objects with managed attributes.

some goals:

tasks that could drive development

some features:

some other design decisions:

General note on syntax

In some languages punctuation characters are also separators, so you aren't required to put a space before or after them, but in Jasper, many punctuation characters mean something different if they are attached to another token as opposed to being surrounded by whitespace. For example, in Jasper,

  x = 3

is not interchangable with

  x=3

The '=' in "x = 3" is called "freestanding". The '=' in "x=3" is called "attached".

Basic function calling syntax

Put the function arguments to the LEFT of the function, separated by spaces.

Example: if f is a function that takes arguments x and y:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======

>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
  y x f

You can pass keyword arguments using keyword=value. The order of keyword arguments doesn't matter. All keyword arguments must go to the right of all positional arguments.

Example:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
  x = 3 [] lb="apple" ins
  x == ["apple"=3]
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

todo: make simpler example

G-constructor syntax

What we call "graphs" in Jasper is a type of value which are what is called in some parts of computer science a "labeled multidigraph with unique node labels and a distinguished node", and where the node and edge labels are arbitrary Jasper values, and some nodes without outgoing edges are arbitrary Jasper values.

To non-CS people, a graph (of either sort) might be called a "network". A graph in Jasper is something that you might draw by drawing a bunch of circles and then drawing some arrows between some of the circles, and then attaching names to some of the circles, and attaching notes to some of the arrows (some arrows might have more than one note). We call the circles "nodes", the arrows "edges", the circle names "node labels", and the notes on the arrows "edge labels".

Formally, (following http://en.wikipedia.org/wiki/Pseudograph) a Jasper __graph__ is an 9-tuple G=(node labels, edge labels, interior nodes, value nodes, edges, s, t, L_n, L_e) where

In other words, a Jasper graph consists a set of interior nodes, which may have names, a set of value nodes, and a set of labeled edges. Value nodes, node names and edge labels may be arbitrary Jasper values. Interior nodes may or may not have a node name; a node name is an arbitary Jasper value that corresponds to exactly one node. A node is either an interior node, or "value node", which is just an arbitrary Jasper value. are any value besides interior nodes. __Edges__ are things that each have a __source__, which is an interior node, and a __destination__, which is an arbitrary node, and one or more __edge labels__, which are arbitary values. One of the nodes is named "root".

A node is reachable from another node if you can start from the one node and get to the other by following intervening edges from source to destination.

A node is connected to another node if you can start from one node and find a sequence of edges such that the first edge's source or target is the one node, and the last edge's source or target is the other node, and each edge's source is either the source or the target of the previous edge. A graph is connected if any pair of nodes is connected. Basically, a graph is connected if you can reach any node from any other node by following the edges, if you're allowed to follow them "backwards". If you draw a graph on paper, it's connected if you can't find any proper subset of nodes such that you can draw a circle around those nodes without intersecting any of the edges.

A Jasper G-constructor can't create any graph value, only some of them, namely (i think) those in which each node is reachable from the "root" node. The values that a single G-constructor can create are kind of like S-expressions in Lisp, except that in addition there is a facility to create cycles.

(I think that) a series of G-constructors, where later constructors make use of values created in earlier G-constructors, can create any connected graph value. By also using a function that merges graphs, (i believe that) any graph value can be created.

G-constructors are constructr surrouded by [] delimiters (can be implicitly closed by indentation).

The outermost node in the constructor is called the "root node". The constructor can only construct one connected component, although other unconnected nodes can be added later by merging graphs.

Example: a graph with only the root node:

  []

Nodes can contain a list of objects, separated by spaces. These objects are considered to be other nodes such that directed edges go from this node to those. These edges are labeled by their position in the list (zero-indexed).

Example: a node that contains a list of the first two even numbers:

  [2 4]

This represents the following directed graph:

   root
    /\
 0 /  \ 1
  /    \
 2      4

If a variable X holds a node, then that node's edges can be traversed using the "." operator.

Example: after putting the above node into "x", x.1 == 4:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
  x = [2 4]
  x.1 == 4    # evaluates to t (true)
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Edges can have multiple labels. To assign an additional label to an edge, use "label = destination".

Example: same as above, but the edge to 2 is labeled "yellow" as well as 0:

  ["yellow"=2 4]

This represents the following directed graph:

            root
             /\
 0,"yellow" /  \ 1
           /    \
          2      4

Any of the labels may be used in traversal:

  x = ["yellow"=2 4]
  x."yellow" == 2

An object pointed to by a node may itself be a node that points to other objects. However, primitive values, such as "2", cannot point to anything.

Example: A node that points to two nodes, one that points to strings describing some fruits, and one that points to strings describing some vegetables.

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
  ["fruits"=["apple" "pear"] "vegetables"=["carrot" "brocoli"]]
                 root
                  /\
      0,"fruits" /  \ 1,"vegetables"
                /    \
               /      \
              /        \
             /          \
            /            \
           /              \
          /\              /\
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
todo num labels         /  \            /  \
=======
         /  \            /  \
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
        /    \          /    \
  "apple"  "pear"  "carrot"  "brocoli"
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
todo num labels
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

"." is left-associative and may be used to traverse: x = ["fruits"=["apple" "pear"] "vegetables"=["carrot" "brocoli"]] x."fruits".1 == "pear"

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
[name | value1, value2, etc] is notation for a node with a node id (global label) name. It is an error (compile-time if possible, but runtime in general) to assign the same name to two different nodes. 
=======
 <code>[name | value1, value2, etc]</code> is notation for a node with a node id (global label) name. It is an error (compile-time if possible, but runtime in general) to assign the same name to two different nodes. 
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Example:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
["x" | fruits=["apple" "pear"] vegetables=["y" | "carrot" "brocoli"]]
=======
<pre>
 ["x" | fruits=["apple" "pear"] vegetables=["y" | "carrot" "brocoli"]]
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
                 root, "x"
                  /\
      0,"fruits" /  \ 1,"vegetables"
                /    \
               /      \
              /        \
             /          \
            /            \
           /              \
          *               "y"
          /\              /\
         /  \            /  \
        /    \          /    \
  "apple"  "pear"  "carrot"  "brocoli"
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

(the * represents the unnamed node in the example)

Labeled nodes may be pointed to using the notation x..name, where x is a variable that refers to the G-constructor.

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======

<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
  x = ["x" | fruits=["apple" "pear"] vegetables=["y" | "carrot" "brocoli"]]
  x.."y".0 == "carrot"
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Within the constructor, ".." may be used with no variable to its left. Using node labels, cycles may be created:

 Example: ["s" | .."s"]
 "s"
 / \
 \_/
 

By referencing parts of other G-constructors, one can create nodes with multiple parents without cycles

Example:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
  x = ["a" | ["b" | 2], 3]
  y = ["c" | x.."b"]
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Now y looks like:

 root,"c"  "a"
        \  / \
        "b"   3
         |
         2
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
Note: the graph in "x" is unchanged! the values of x and y have not been "linked" together in any way, it is as if a copy was made of some of the contents of x and put into y. If you don't want time and memory to be spent making a copy, and you don't have any more use for the graph in x, then don't use the variable "x" afterwards and the compiler will probably notice and optimize under the hood by just using the part of memory that it used to call "x" for y and adding node "c" in-place. If you want to make sure, use the variable "x" throughout, "x = ["a" | ["b" | 2], 3]; x = ["c" | x.."b"]", which guarantees that the compiler will mutate x in-place rather than copying.
=======
Note: the graph in "x" is unchanged! the values of x and y have not been "linked" together in any way, it is as if a copy was made of some of the contents of x and put into y. If you don't want time and memory to be spent making a copy, and you don't have any more use for the graph in x, then don't use the variable "x" afterwards and the compiler will probably notice and optimize under the hood by just using the part of memory that it used to call "x" for y and adding node "c" in-place. If you want to make sure, use the variable "x" throughout, "<code>x = ["a" | ["b" | 2], 3]; x = ["c" | x.."b"]</code>", which guarantees that the compiler will mutate x in-place rather than copying.
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
  In any case, the compiler may choose to defer the copy unless and until it wants to do it. Unless x is a mutuable variable, the compiler will probably simply internally refer to x when "b" is called for.

Note: only the part of the graph that is reachable by a directed path from x.."b" is included in y.

Note: the node labels are only available from variables bound to the G-constructor in which they were created:

Example:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
  x = ["a" | ["b" | 2], 3]
  y = ["c" | x.."b"]
  x.."b"    # succeeds
  y.."c"    # succeeds 
  x.."c"    # error
  y.."b"    # error
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

The reason it works this way is that a G-constructor actually returns not the root node, but rather an "index node object", which is a node that contains an assoc table from node labels to nodes. one of the nodes is labeled "root". for convenience, "." is actually a shortcut for "..root." ".." is used to directly access the index node.

To create a variable with all the labels, use the midx ("merge index") command, which takes a list and returns a list of the same length. Each item in the return list contains the same node as the corresponding item in the input list; but all items in the return list can access any of the node names anywhere in the input list:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
  [x y] = ([x y] midx)
  x.."c"    # succeeds
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Again, however, it should be noted that the values of the nodes are not "linked".

It is an error if there is a name clash between the labels of any of the nodes being merged (except for the label "root"). This can be avoided when names are hardcoded by using symbols for names (todo). When labels are not symbols, use of midx generates a compiler warning. When labels are dynamically computed at runtime, errors can be avoided by using the midxrn function which renames clashing names and returns a table listing the new names (todo), or by using midxic ("merge index ignore clash"), which resolves name clashes differently for each variable in the list by preferring that index's names over incoming names, and then preferring name bindings from the beginning of the list over names from the end, or by using midxo ("merge index overwrite"), which resolves name clashes uniformally for all variables in the list (i.e. all variables end up with copies of the same index) by preferring name bindings from the beginning of the list.

As you might guess from the compiler warning, my recommendation is that you avoid midx except for when you are using hardcoded labels (preferably symbols). Usually midxrn is the right choice otherwise.

Within a graph, the reserved word "this" always refers to the current node.

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
 Example: a node with a self-loop may also be created as follows: [this]
=======
Example: a node with a self-loop may also be created as follows: <code>[this]</code>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Within a G-constructor, the reserved word "root" refers to the root node. Example:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

[1, [2, root]]

    root _
     /\   |
    /  \  |
   1   /\_|
      2  
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Using the "unshadow" token operator, "^", on "this", the (lexical) parent node may be referred to. Repeating the unshadow operator allows reference to the (lexical) grandparent.

Example:

 [1, [2, ^this]]
    root _
     /\   |
    /  \  |
   1   /\_|
      2  
 [1, [2, ^this.0]]  
    root 
     /\   
    /  \  
   1   /\
      2  1
  1. note; the ^this.0 is evaluated at the time of graph construction; if one of the 1s is changed later, the other wont be affected
 [1, [2, [3, ^^this]]]
    root ___
     /\     |
    /  \    |
   1   /\   |
      2 /\  |
       3  \_|

Not all edges of a node have to have integer labels (in fact, none of them do). To separate those edges with integer labels from those without, use the "--" symbol. Edges with integer labels go on the left. Edges on the right must have an explicit label. The integer labels are no different from other labels; the -- syntax just tells the constructor not to automatically add them.

  [1 -- "yellow"=2]
            root
             /\
          0 /  \ "yellow"
           /    \
          1      2
  [-- "yellow"=2]
            root
             /
   "yellow" /  
           /  
          2   

many different edges from the same node may all point to the same destination object:

  [1, ["red"=root, "yellow"=root]]
        <-------------|
    root<--           |
     /\   |           |
    /  \  |2, "yellow"|
   1   /\_|           |
      |               |
      |_______________|  
           1, "red"

(btw the only reason i'm not drawing arrows on most edges here is that it's hard to do -- all edges are directed)

An edge may have multiple edges with the same label, but in this case . will only follow the "first" one (first is the one with the lowest integer label; if all the edges with the given label are non-integer, todo)

To add an edge programmatically, use "ins":

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

x = [1 2] x = 3 x ins x == [1 2 3] x = x "red"="apple" ins x == [1 2 3 "red"="apple"]

  1. alternative x = [1 2 3] x = "apple" x lb="red" ins x == [1 2 3 "red"="apple"]
  2. use i=n keyword arg to ins to not assign the next integer to new label x = "banana" x lb="yellow" i=n ins x == [1 2 3 "red"="apple" -- "yellow"="banana"]
  3. or, alternatively, if x.__ordered = f, ins will not assign an integer: x = [1 2 3] x.__ordered = f x = x "yellow"="banana" ins x == [1 2 3 -- "yellow"="banana"]
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

To get or set a node's label use its "lb" edge:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

x = [1 [2]]
x.lb = "apple"
x == ["apple" | 1 [2]]

=======
<pre>
 x = [1 [2]]
 x.lb = "apple"
 x == ["apple" | 1 [2]]
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

To operate on nodes other than root, use assignment syntax:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

x = [1 [2]]
x.1.___lb = "apple"
x == [1 ["apple" | 2]]

=======
<pre>
 x = [1 [2]]
 x.1.___lb = "apple"
 x == [1 ["apple" | 2]]
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

To access a node which represents an edge (this is called "reifying" the edge), use the '^.' operator in place of '.'. The reified edge has labels "src", "dst", "lb". Note that the contents of lb is a list:

 x = [1 "yellow"=2]
 x^.1.dst == 2
 x^."yellow".lb == [1, "yellow"]

You can change an edge's labels or even its source or destination:

 x = [1 "yellow"=2]
 x^."yellow".lb = [3 "red"]
 x == [1 -- [3,"red"]=2]

To insert the contents of one list into another, you can use the @ operator:

  x = [2 3]
  y = [1 @x 4]
  y == [1 2 3 4]

example: a single node with value "10": ex = [10] ex.n == 10

example: a single node that points to itself:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

ex = ['s

ex = [this]
s]
<<<<<<< /root/website/lists/.unison.merge1-jasper.txt
</pre>
||||||| /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
</pre>

todotodo
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

example: a list

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

ex = ["apple" "banana" "cherry"] ex = ["apple" "banana" "cherry"] ex.0 == "apple" ex.1:2 = ["banana" "cherry"] ex = $[apple banana cherry] ex = "apple", "banana", "cherry" ex2 = ["grapefruit", @ex] ex2 = ["grapefruit","apple","banana","cherry"] fruit2 = "banana"; ex = $[apple `fruit2 cherry] fruit23 = $[banana cherry]; ex = $[apple `@fruit23]

example: an association table ex = [ apple = red banana = yellow cherry = red ex = assoc $[[apple red] [banana yellow] [cherry red]] ex = assoc $[ apple red banana yellow cherry red ex = assoc [ "apple" "red" "banana" "yellow" "cherry" "red"

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

todotodo

$[] means that tokens will be interpreted as strings, not variable names, except for tokens prefixed by ` ; also, like [[]], u can separate by spaces


Function definition

Just use an =s sign to write an equation. The function on the left will be defined in the current namespace.

To make f work like "+" (although f won't be infix):

 y x f = x y +

Partial function application

If function f takes 2 arguments, and you want to call it with its first argument x and its second one y, then

  result = y x f

is the way to do that. However, you can also do

  g = x f

In this case, the value of "g" is a (partially applied) function, namely, the function f but with its first argument fixed to y. That leaves one argument to be specified, so g is a function that takes one argument. You can call g just like any function. The result of g is defined by

  y g == y x f

Jasper's expressions are right-associative, for example,

  y x f == y (x f)

So, in Jasper, passing multiple arguments to a function is equivalent to passing it just one argument and creating a partial function, then passing that function a second argument to make another function, etc.

Infix operators

The predefined infix ops are '==', '!=', '||', "&&', '=~', '>', '<', '>=', '<=', '<==>' ("spaceship operator"), 'in' (todo: find others to include). An infix operator has the effect of putting parentheses around everything to its left (within its containing subexpression) and of putting parentheses around everything to its left (within its containing subexpression). Example:

<<<<<<< /root/website/lists/.unison.merge1-jasper.txt
b/c then f in 0-ary "as written". Do we care (yes)? What is the most readable fix?

)

An exception to the restriction is when a 0-ary function returns another function; in this case no grouping is needed. 

(todo: work that in above)

== Infix operators ==
The predefined infix ops are <code>'==', '!=', '||', "&&', '=~', '>', '<', '>=', '<=', '<==>' ("spaceship operator"), 'in' (todo: find others to include)</code>. An infix operator has the effect of putting parentheses around everything to its left (within its containing subexpression) and of putting parentheses around everything to its left (within its containing subexpression). Example:

||||||| /root/.unison/backup/website/lists/.bak.1.jasper.txt
b/c then f in 0-ary "as written". Do we care (yes)? What is the most readable fix?

)

An exception to the restriction is when a 0-ary function returns another function; in this case no grouping is needed. 

(todo: work that in above)

== Infix operators ==
The only infix ops are '==', '!=', '||', "&&', '=~', '>', '<', '>=', '<=', '<==>' ("spaceship operator"), 'in' (todo: find others to include). An infix operator has the effect of putting parentheses around everything to its left (within its containing subexpression) and of putting parentheses around everything to its left (within its containing subexpression). Example:
=======
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
  2 1 + <= (2 5 +) 5 -
  -> 
  (2 1 +) <= ((2 5 +) 5 -)
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
Users can't define new infix operators or "infixify" functions.
=======
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
If there are multiple infix operators, they must be disambiguated with another grouping construct; an expression like "a || b == t" is illegal.
=======
Users can define new infix operators but they must be named by symbols starting or ending with of at least one of '<code>=|&~<></code>' and which don't contain any characters besides those and '!-'. User-defined non-infix operators may not start or end with '<code>'=|&~<></code>'. This makes it easy for readers to classify unfamiliar operators as infix or not by sight.

If there are multiple infix operators, they must be disambiguated with another grouping construct; an expression like "<code>a || b == t</code>" is illegal.
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Note: subeq and sub (subset containment) are expressed by <= and <.

Subtraction

Negative number literals are written with a '-' attached on the left. A freestanding '-' denotes the subtraction function, which is a normal postfix function.

Fancy grouping syntax

Parentheses group in the usual way.

Without any grouping, expressions are right associative. So

  z y x f = z (y (x f))
  
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
(Freestanding) '/' is a grouping construct that has the effect of putting parentheses around everything to its left (until it hits an infix operator or the boundary of the containing subexpression). If there are multiple ones on a line, the one on the left "acts first". It is the equivalent of the Haskell's '$'. So, for example,
=======
(Freestanding) '<code>//</code>' is a grouping construct that has the effect of putting parentheses around everything to its left (until it hits an infix operator or the boundary of the containing subexpression). If there are multiple ones on a line, the one on the left "acts first". It is the equivalent of the Haskell's '$'. So, for example,
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
   x (y g / f) h == x ((y g) f) h
=======
   x (y g // f) h == x ((y g) f) h
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
',' is a grouping construct that has the effect of putting parentheses around the clause to its left, and also putting parentheses the clause to its right, where a clause is everything until you hit the beginning or the end of the containing subexpression, or an infix operator, or one of ',', '/', skipping over subexpressions.
=======
',' is a grouping construct that has the effect of putting parentheses around the clause to its left, and also putting parentheses the clause to its right, where a clause is everything until you hit the beginning or the end of the containing subexpression, or an infix operator, or one of ',', '//', skipping over subexpressions.
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

','s may be attached or freestanding.

For example,

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
 (2 1 f  , 4 3 g  , h)   (2 1 f  , 4 3 g  , j)  a / 5 b / 6 c
=======
 (2 1 f  , 4 3 g  , h)   (2 1 f  , 4 3 g  , j)  a // 5 b // 6 c
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
 ==
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
 ((2 1 f ,  4 3 g  , h)   (2 1 f  , 4 3 g  , j)  a) 5 b / 6 c
=======
 ((2 1 f ,  4 3 g  , h)   (2 1 f  , 4 3 g  , j)  a) 5 b // 6 c
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
 ==
 (((2 1 f ,  4 3 g  , h)   (2 1 f  , 4 3 g  , j)  a) 5 b) 6 c
 ==
 ((((2 1 f)   (4 3 g) (h))   ((2 1 f) (4 3 g) (j))  a) 5 b) 6 c
 ==
 ((((2 (1 f))   ((4 (3 g)) h))   (((2 (1 f)) ((4 (3 g)) j))  a)) (5 b)) (6 c)

(Attached) '.' is a weird grouping construct and a special infix operator. It "binds tightly", like an infix operator, and which has the effect of putting a '(' to the left of the subexpression or function immediately to its left and a ')' to the right of the subexpression or function immediately to its right. '.'s are left-associative with other '.'s. It must be attached to both its left and right operands. What it does is to evaluate the thing on its right, and then feed it to the thing on its left

So,

 3 + x.y.z.w + 2 == 3 + (w (z (y x))) + 2

So it reverses the things embedded in the sequence. In addition, '.' has a special meaning when it is found on the left hand side ("lhs") of a freestanding '='. We'll see later that '.' is useful for things that work like attribute access (struct field access), or things that work like indexing into a list, or things that work like looking up a value from an association table based on a key, or things that work like tree or graph traversal.

*functions

If a function's name starts with *, for example "*func", then first the *function takes as many arguments to the left as needed to partially apply to func in order to make it binary, and then *function takes all of the arguments to its left, up until '', ',', or the edge of the containing subexpression, and combines them in a foldr with the function operation being the partially appiled func, with the rightmost element being the initial accumulator value.

In English, this means that putting * in front of a binary function makes it take a list of arguments and act as if it were an tightly binding, right-associative infix operator put in between each argument.

For example, '*+' is a *function with '+' as the underlying function.

 1 2 3 4 *+ == what in mathematical notation is written 1+2+3+4
 1 2 3 4 ** == what in mathematical notation is written 1*2*3*4
 1 2 3 4 *binary_func == what in mathematical notation is written binary_func(1,binary_func(2,binary_func(3,4)))
 1 2 3 4 *trinary_func  == 
    y x f = 4 trinary_func
    1 2 3 *f
       == what in mathematical notation is written trinary_func(4,1,triary_func(4,2,3))

How to read Jasper expressions

If there is just one symbol then you're done, if there's just one subexpression then recurse :)

First, if there is an infix operator, then it divides everything to its left from everything to its right.

For the most part, the computation proceeds from the left to the right.

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
Next, note each ')' or '/'. The things immediately to the left of these, and also the last thing on the right side of the line, are the functions that will be acting on arguments, the "active functions". These things may be symbols denoting functions, or thery may be subexpressions which evaluate to functions.
=======
Next, note each ')' or '<code>//</code>'. The things immediately to the left of these, and also the last thing on the right side of the line, are the functions that will be acting on arguments, the "active functions". These things may be symbols denoting functions, or thery may be subexpressions which evaluate to functions.
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
Look at the rightmost active function on the line -- this is the last function that will be applied, taking as arguments all of the other things to its left, up to any /s (if there is a /, then everything to its left is the last argument of the current active function). If there is a /, then look to its left to find the active expression, and look over it. Repeat. Now you have a general, top-down sense of what functions are demanding the various arguments in the expression.
=======
Look at the rightmost active function on the line -- this is the last function that will be applied, taking as arguments all of the other things to its left, up to any <code>//</code>s (if there is a <code>//</code>, then everything to its left is the last argument of the current active function). If there is a <code>//</code>, then look to its left to find the active expression, and look over it. Repeat. Now you have a general, top-down sense of what functions are demanding the various arguments in the expression.
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Now start at the left and read left-to-right, to understand how each subexpression is calculated. This is a bottom-up viewpoint, in the sense that you will start out by seeing how each subexpression is calculated, and then after progressing through each set of arguments, you will see the active function that eats those arguments.

When there are ,s, they separate two subexpressions which are each arguments of the same active function.

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
When there are /s, the things to the left of the / are computed first, and then they are fed to the active function controlling the / as its final argument. So /s represent a pipeline (or composition of functions) which can be read from left to right.
=======
When there are <code>//</code>s, the things to the left of the <code>//</code> are computed first, and then they are fed to the active function controlling the <code>//</code> as its final argument. So <code>//</code>s represent a pipeline (or composition of functions) which can be read from left to right.
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
Sequences of things separated by '.'s are, like '/'s, pipelines where the thing on the left is calculated first, and then the result is fed to the thing on the right. The difference is that the "thing on the left" is as narrow as possible, rather than as wide as possible as with '/'. Technically,  '.' is an active function, but TODO prob here
=======
Sequences of things separated by '.'s are, like '<code>//</code>'s, pipelines where the thing on the left is calculated first, and then the result is fed to the thing on the right. The difference is that the "thing on the left" is as narrow as possible, rather than as wide as possible as with '<code>//</code>'. Technically,  '.' is an active function, but TODO prob here
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

The intent of '.' is for it to be used for things where it is easier to think about what is going on by reading the things in between the '.'s from left to right. For example, imagine that lookup in a 2-D array is done like this: pass the row number to a row lookup function, and then, representing that row, you get back a "column lookup function" for that row. Now pass the column number to the column lookup function, and it returns the value at that location. So, to lookup row 5 column 2, you do "2 (5 row_lookup)"; "(5 row_lookup)" evaluated to the column lookup function for row 5, and you pass 2 to that, and get back the value stored at row 5, col 2. You could write this "row_lookup.5.2" which is shorter and seems to be easier to read.

Example:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
 (2 1 f  , 4 3 g  , h)   (1+1 1 f  , 4 x.y.z g  , j)  a / 5 b / 6 c
=======
 (2 1 f  , 4 3 g  , h)   (1+1 1 f  , 4 x.y.z g  , j)  a // 5 b // 6 c
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Here we have 3-stage pipeline with active functions a,b,c. First "(2 1 f , 4 3 g , h) (1+1 1 f , 4 x.y.z g , j) a" will be computed, then its result will be used as the last argument of b (with 5 being the other argument to b), and finally the result of that will be used as the last argument of c.

a is taking 2 arguments, each subexpressions. The active function in the subexpression which computes a's first argument is j and the active active function in the subexpression for a's last argument is h.

h itself takes two arguments, given by (4 3 g) and (2 1 f). j also takes two arguments. j's first argument, "4 x.y.z g", is a subexpression which has an active function g which takes two arguments, x.y.z and 4. "x.y.z" means "z (y x)". j's last argument is "(1+1) 1 f".

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
=== Why? ===
Jasper is "backwards" from most programming languages so that the main flow of the computation within an expression goes left-to-right rather than right to left. This means that to get a top-down sense of what is going on, you must read Jasper from right to left, and to get a bottom-up sense, read it from left to right.

I find that for short or easy to understand expressions, I want to read it once top-down and then I understand. For long or hard to understand expressions, I find that I first glace through it to get a top-down overview, and then I slowly read through the expression bottom-up. It is easier to read from left-to-right as compared to right-to-left, because the spelling of each word is left-to-right. For a short expression, the difference doesn't really matter, because it's easy to move your eyes to either the leftmost or the rightmost end of the expression.

So, traditional programming languages are good for the top-down phase but bad for the bottom-up phase, whereas Jasper is good for the bottom-up phase but bad for the top-down phase. Although the top-down phase is more common, this is due to the prevalence of expressions that are short and easy to read in any case; it seems that the long, difficult expressions will be easier in Jasper.

These are just personal observations which have not been thought about much or checked extensively or objectively.


The <code>//</code> operator is inspired by Haskell's $ and is a concise, readable alternative to the common "pipeline" situation described above. The . operator mimics how object attribute access reads in other languages such as Python. The ',' acts much like it does in languages with a f(x,y) syntax; it allows you to separate subexpressions without typing a zillon parentheses (also, it is easier to read something with parens at a high nesting level with commas inside them then it is to read something using nested parens, i.e. parens on both nesting levels).

>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Keyword arguments

 exponent base g = base^exponent
 1 2 g # == 2
 base=2 exponent=1 g # == 2

If no value is specified for a keyword argument in a function call, then 't' is assumed to be the value. This saves you one character when sending optional arguments to functions which are really just binary switches that turn on some non-default behavior, e.g. word ignorecase= find

Keyword arguments must be the "first", i.e. the rightmost, arguments to the function (although a partially applied function can still accept new keyword arguments).

  exponent base g = base^exponent
  exponent=1 2 g # is an error; keyword argument is not first
  exponent=1 base=2 g # == 2
  2 exponent=1 g # == 2
  1 base=2 g # ==2

Note that if you use a keyword to assign to an argument, that that argument is "skipped over" when it's position comes up, requiring care in reading:

 toMultiplyBy toSubtract toStartWith h = (toStartWith toSubtract -)*toMultiplyBy
 
 3 2 1 h # == -3
 3 1 toSubtract=2 h # == -3; the same, because toSubtract was skipped
  1. that is to say, toMultiplyBy toSubtract toStartWith h == toMultiplyBy toStartWith (toSubtract=toSubtract h)

Usually, once you apply an argument to a function, you can't change it later with a keyword. If you want to do that, use the function applyArgsAsDefault:

 1 base=3 base=2 g # error; base assigned to twice
 1 base=2 base=2 g # error; base assigned to twice
 a = (base=2 g); 1 base=2 a # error; base assigned to twice
 a = (2 g); 1 base=2 a # error; base assigned to twice
 a = [2] g applyArgsAsDefault; 1 base=3 a # == 3
 a = base=2 g applyArgsAsDefault; 1 base=3 a # == 3

Otherwise, if you assign an argument to an unused keyword, it has no effect (but it does generate a compiler warning) (but note: functions which take a "*more" argument can read all keyword arguments given to them, whether or not they use that argument in their signature).

 1 2 blah=4 g # == 2
 A "*more" argument must be the last (leftmost) in the function definition, and signals that the function does something with arbitrary keyword arguments. Within the function body, the unasked-for keywords and their values are edges and children of a node assigned to *more.
 "unasked-for keyword"="val" "hi" printFirstKeyword # hi\nunasked-for keyword

Default arguments

In function definitions, default arguments be the "first", or rightmost arguments. Arguments which have defaults ARE NOT positional, and can only be given by keywords.

 x=1 f = x + 3
 f == 4
 5 f # is an error; the x argument is not positional, only keyword
 x=5 f == 8
 exponent base=e g = base^exponent
 
 1 g == 2.718...
 1 base=2 g == 2

Neutralizing a function

If you have given a function all its required arguments (i.e. those without defaults), but rather than evaluating it, you want it to sit as a partially applied function waiting for possible default overrides, you can "neutralize" it with the "neu" higher order function. A neutralized function eats its arguments like normal, but then when all its required args have been supplied, it yields itself (with the arguments applied), rather than whatever value it is supposed to yield. Then to make it "go" later, us "unneu".

 exponent base=e g = base^exponent
 1 (g neu) #== 1 (g neu)
 (1 (g neu)) unneu # == 2.718...
 a = 1 (g neu); b = base=2 a; b unneu # == 2

sq

todo: NO, this stuff should be always, sq is for strict eval

sq (short for "sequence") labels a body of consecutive lines that will be written as if they will executed in sequence. For example,

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

x f = sq y = x + 3 z = y * 2 z + 1

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

This looks like an imperative sequence of steps but actually the compiler will translate it to an expression; the value of the last line will be returned as the value of the expression, but with variable binding in the previous line substituted in to that, and then the variable binding in the previous line substituted in to that, etc.

The effect is similar to this Haskell code (todo: check 4 mistakes):

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

f x = let y = x + 3 in let z = y * 2 in z + 1

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

sq is similar to Haskell's "do" except that it doesn't use monads or produce a monadic type; it's the let-binding syntactic sugar of Haskell's do without the monads. sq also has some extra syntactic sugar, see below.

Convenience mutation

Within sq,

 x = 5
 x = x + 1
 x pr

->

 x = 5
 x2 = x + 1
 x2 pr

In place convenience mutuation

Within sq, any function that takes and returns something of the same type can be written alone on a line, along with arguments, with !! at the end of the line:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

x sort !! -> x = x sort -> (reducing using convenience mutation, as described above) x2 = x sort .. ('x's below replaced by 'x2's) ..

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

x= notation

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

x = 3 x += 2 x == 5

x = 3 x y f = x y * x f= 2 -> x = x 2 f -> x = x 2 * -> convenience mutuation x == 6

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

assignment to graph objects

'.' must be the operator on the top level of the l-value

 g = [3 4]
 g.0 = 1
 -> g = 1 0 g __set 
 -> ... (convenience mutation)
 g.0 == 1

inc/decrement

A line containing an expression whose top level consists of a symbol or value attached to the increment (++) or decrement (--) operators is short for an '='s which applies that operator

 x++
 ->
 x = x ++
 g = [3 4]
 g.1++
 ->
 g = [3 4]
 g.1 = g.1 ++
 -> ... (assignment to graph objects)
 g.1 == 5
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt

=======
----
end of sq section
----
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Pronouns

"it"

When you call a function (or use an infix operator) inside an sq, the symbol "it" may (or may not) be rebound by that function. That is, the function gets to reach out of its lexical context and change the value of "it" in your lexical context.

For example, if you match a string against a regular expression using the =~ comparison operator, "it" is bound to a list of matches.

 "hi there" =~ r<<th..e>>
 it.0.txt == "there"

This is similar to how Perl binds $0, $1, $2, etc when you match a regex.

"it" may be rebound once each line (using convenience mutation).

 "hi there" =~ r<<th..e>>
 "hi dude" =~ r<<d..e>>
 it.0.txt == "dude"

If multiple functions or operators on a single line try to rebind "it", then the outermost one wins.

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
To convert any function that binds something to "it" into a function that returns an ordered table, where the label of the first element is x' and the label of the second element is it' and the first element is the value that the function returns, and the second element is the value that the function binds to "it", use the "withit" function or the "it-" token operator. This allows you to get those "it" values when you are not in an sq block:
=======
To convert any function that binds something to "it" into a function that returns an ordered table, where the label of the first element is x' and the label of the second element is it' and the first element is the value that the function returns, and the second element is the value that the function binds to "it", use the "giveit" higher order function. This allows you to get those "it" values when you are not in an sq block:
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
 f = "hi dude" -it-=~ r<<d..e>>
 f.0 == t
 f.1.0.txt == "dude"
=======
 g = "hi dude" r<<d..e>> ((=~) giveit)
 g.0 == t
 g.1.0.txt == "dude"
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
 g = "hi dude" r<<d..e>> ((=~) withit)
 g == f
=======
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

$$

<<<<<<< /root/website/lists/.unison.merge1-jasper.txt
$$, outside of a list, is replaced with:

  fn i=n s=n z=n y=n x=n :

i.e.

 f ($$ x g) 
 ->
 f (fn i=n s=n z=n y=n x=n : x g)

in order to make functions passed to higher order functions easy to read, functions that require functional arguments (call these 'subfunctions') are encouraged to call the subfunctions that are passed in with keywords. The following conventions obtain:

* x: if each call of the subfunction passes in some input which is interpreted as the primary content being operated on, assign this to 'x'
* i: if some container or larger structure is being iterated over or constructed or operated on, and some input is being passed to the subfunction to indicate which piece or index or key or address or location within the larger structure is currently the focus of attention, then assign this input to 'i'
* s: if some state is being passed into the subfunction, for example if the subfunction is being called multiple times, then assign this input to 's'
* y and z are provided for undefined uses
* if none of the above conventions for x,i,s apply and if only 3 arguments are required, then don't use x,y,z,i,s keyword arguments, and when constructing a subfunction, $$ may be used, which will have the effect of assigning the three arguments to the subfunction to x,y,z
* if none of the above conventions for x,i,s apply and if more than 2 other arguments are required to be passed to the subfunction, or if some of the conventions apply but more than 2 arguments for other undefined uses, then use of $$ is discouraged; it is bad form to use it in a way such that s or i are put to some use other than in fitting with their conventions, and it is bad form to use x in a way other than in fitting with its convention if i or s is used.

For example, foldr is defined like this:

<pre>
foldr  { [b] a [a b a] = a}
xs0 z0 f foldr = xs0 z0 rgo
  [] s rgo     =  s
  (xs x ins) s rgo = xs (s=s x=x f) rgo
</pre>
||||||| /root/.unison/backup/website/lists/.bak.1.jasper.txt
$$, outside of a list, means "enclose the contents of the enclosing subexpression with":
=======
$$, outside of a list, is replaced with:

  fn i=n s=n z=n y=n x=n :

i.e.

 f ($$ x g) 
 ->
 f (fn i=n s=n z=n y=n x=n : x g)

in order to make functions passed to higher order functions easy to read, functions that require functional arguments (call these 'subfunctions') are encouraged to call the subfunctions that are passed in with keywords. The following conventions obtain:

* x: if each call of the subfunction passes in some input which is interpreted as the primary content being operated on, assign this to 'x'
* i: if some container or larger structure is being iterated over or constructed or operated on, and some input is being passed to the subfunction to indicate which piece or index or key or address or location within the larger structure is currently the focus of attention, then assign this input to 'i'
* s: if some state is being passed into the subfunction, for example if the subfunction is being called multiple times, then assign this input to 's'
* y and z are provided for undefined uses
* if none of the above conventions for x,i,s apply and if only 3 arguments are required, then don't use x,y,z,i,s keyword arguments, and when constructing a subfunction, $$ may be used, which will have the effect of assigning the three arguments to the subfunction to x,y,z
* if none of the above conventions for x,i,s apply and if more than 2 other arguments are required to be passed to the subfunction, or if some of the conventions apply but more than 2 arguments for other undefined uses, then use of $$ is discouraged; it is bad form to use it in a way such that s or i are put to some use other than in fitting with their conventions, and it is bad form to use x in a way other than in fitting with its convention if i or s is used.

For example, foldr is defined like this:

<pre>
foldr  { [b] a [a b a] = a}
xs0 z0 f foldr = xs0 z0 rgo
  [] s rgo     =  s
  (xs x ins) s rgo = xs (s=s x=x f) rgo
</pre>

You can write a fold that finds if any item in a list is even like this:

  ($$ s || x 2 mod // !) foldr

(todo: check for mistakes) the 's' and the 'x' help the reader see which argument (s) is the boolean state which is being passed between invocations of the anonymous function, and which argument (x) is the list item.

== List comprhensions ==
<pre>
<<[1,2,3] | x>=2 >> == [2,3]

<<x*2 : [1,2,3]>> == [2,4,6]

<<x*2 : [1,2,3] | x>=2 >> == [4,6]
</pre>
Uses x pronoun.

== Graph comprehensions ==
<pre>

<<< : list comprehension over leaves, any terminator
<flavor<< : list comprehension over leaves, flavor terminator
<!flavor<< : list comprehension over leaves, non-flavor terminator

<<<< : same but all nodes
...
...
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
<<<<<<< /root/website/lists/.unison.merge1-jasper.txt
You can write a fold that finds if any item in a list is even like this:

  ($$ s || x 2 mod // !) foldr

(todo: check for mistakes) the 's' and the 'x' help the reader see which argument (s) is the boolean state which is being passed between invocations of the anonymous function, and which argument (x) is the list item.

== List comprhensions ==
<pre>
<<[1,2,3] | x>=2 >> == [2,3]

<<x*2 : [1,2,3]>> == [2,4,6]

<<x*2 : [1,2,3] | x>=2 >> == [4,6]
</pre>
Uses x pronoun.

== Graph comprehensions ==
<pre>

<<< : list comprehension over leaves, any terminator
<flavor<< : list comprehension over leaves, flavor terminator
<!flavor<< : list comprehension over leaves, non-flavor terminator

<<<< : same but all nodes
...
...

<<<<< : same but interior nodes

</pre>
how to work in graph patterns?
||||||| /root/.unison/backup/website/lists/.bak.1.jasper.txt
  fn p0
=======
<<<<< : same but interior nodes

</pre>


todo: how to work in graph patterns?
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Referential transparency

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
&
=======
Jasper is supposed to be a referentially transparent language, like Haskell -- except that supports some constructs which do not eem to be referentially transparent, but which can be thought of as syntactic sugar for expressions which are (since the power of all general programming languages is in some sense equivalent, it is certainly debatable whether this makes Jasper any more referentially transparent than imperative languages, which claim no pretensions of referentially transparency). Some of the simplest of those constructs are the sq syntax detailed above. Others are part of the error handling facilities. Two other complex ones are covered here.

"&" is used as a prefix for variables that refer to state, "references". Any function that references a & variable (references a reference, heh heh) must declare itself to be using state, and declare "which" state (or states) it uses (todo: define syntax for this); the compiler is prompted by this declaration to, under the hood, convert the function's type to monadic type with a monad similar to Haskell's state monad. This change in type allows the compiler to make sure that other related functions which also, covertly, carry state are declared as such. The compiler API allows IDEs and users to query which functions are "contaminated" by (which) state.

Another way in which referential transparency would be broken is by the use of I/O. Jasper has an equivalent to Haskell's I/O monad, and when you use an I/O function in your function, your function is transparently converted to be within the I/O monad. As with state, the compiler keeps track of which other functions are tainted and can tell you or your IDE; however, no explicit declaration is needed to do I/O.
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
monads
=======
All the business about stacking the different monads is handled by the compiler.
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Graph assignment

[] form

@ form

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
== Graph mutation ==
x.y.z = 3


=======
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Token operators

Unary postfix token operators

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
todo

>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

These bind tighter than infix operators and

! : negation (boolneg) t! == f

!f : apply f x maketrue = t f!maketrue == t

modules

A module is a block of code which shares a namespace (the "module namespace") and which exports a namespace (the "module's exported namespace"). Modules may span multiple files, and one file may contain many modules, but a module may only span files within one directory. Module names should be globally unique, although in the case of a conflict, the module search path defines which module definitions shadow which others.

The contents of a module's namespace is explicitly defined in the module code. The contents of a module's exported namespace is implicitly defined. A module's exported namespace includes the same names as in its own namespace, except for:

A module begins at the first line in a file that is not a comment or a % directive, or at a module declaration. A module declaration looks like

 %module modulename

A module continues until the next module declaration or the end of the file.

A module which is implicitly begun by code at the beginning of a file, rather than being explicitly begun by a %module line, is given a module name which is the name of the directory which contains the file.

Modules may have a version. A version is a sequence of integers separated by dots, with the last element being an integer (not a dot). A version with less dots is equivalent to a version with more dots with "0"s in between them. A total ordering on versions is given by: version A > version B iff they differ and the first differing integer, reading from left to right, is larger in A. For example, 1.1.1 > 1.1 > 0.1 > 0, and 1 = 1.0 = 1.0.0. A module's version is assigned by the %ver directive. Modules without a %ver directive are version 0. Examples:

%ver 1 %ver 0.0.1

If the line immediately after a module declaration contains a ./ /.-delimited comment, then its contents is considered the modules's docstring. If the same module spans multiple parts, and if multiple parts have such a comment, they are all concatenated in unspecified order.

Files can have docstrings too -- if the first line of the file, excluding any lines beginning with #, contains a comment, that is the file's docstring.

Module names can't begin with the "_" character.

import

"imp" (import) is used to add the contents of some other module's exported namespace into the current module's namespace.

Forms of import (these can be mixed and matched): %imp modulename #import modulename

 %imp modulename/version
   #import modulename, require it to be version "version"
 %imp modulename/minversion:maxversion
   #import modulename, require it to be some version in between minversion and maxversion, inclusive
 %imp modulename/minversion:suggested_version:maxversion
   #import modulename, require it to be some version in between minversion and maxversion, inclusive, and
   #if "suggested_version" is available, use that one
 %imp exp modulename
   #import modulename, and also place the imported names into this module's exported namespace
 %imp modulename1 modulename2
   #import multiple modules
 %imp exp modulename1 modulename2
   #import multiple modules, and also place the imported names into this module's exported namespace
 %imp exp modulename=
   #import modulename, but prefix the imported names with modulename.; for example, "a" becomes "modulename.a"
 %imp exp modulename=newname
   #import modulename, but prefix the imported names with newname

To import a module's own namespace, rather than its exported namespace, put a "_" in front of it's name. This causes a compiler error unless the "--exposeprivates" command-line option is given to the compiler.

Pattern matching

Jasper patterns are sort of like regular expressions, generalized to match on graphs. They are used in three ways in Jasper:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

1) To define functions by cases, using pattern matching as a convenient syntax to define the cases 2) To constrain the shapes of data interfaces 3) As part of the specification of graph transformations

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Note that since Jasper is lazy, some nodes may have infinitely many arcs, in which case such an attempt to match such a structure would result in an infinite loop as Jasper attempted to check every arc. However, uses #2 and #3 don't involve checking every arc and so would still be relevant in such a situation.

To match a pattern against something, use the infix "=~" comparison operator, which returns a boolean, and in the case of a match also binds, using convenience mutation, each of the pattern variables in the pattern to their values in the match. Note: for type safety, the compiler must be able to know what the symbols will be and what their types are. If you hardcode the pattern, the compiler will infer this. But, in case you want to dynamically construct a pattern within the program, a mechanism is provided to statically specify the pattern variables and their types; see below.

When =~ is used inside an sq, then in the case of one or more matches, the contents of "it" will be set to a list of tables. Each item in the list is a table that corresponds to one match. Each table maps each pattern variable to its value in that match.

Jasper patterns are written within {}s.

Jasper patterns look sort of like graph constructors and match top-down, that is, whatever you write will first be matched against the node you are matching against, and then the children of the root of the pattern will each be matched against each child of the node you are matching against, etc, recursively.

The empty pattern always matches:

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======

>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
  x =~ {} 
  == t

All implementation types are Jasper patterns. For example, {Bool}.

You can define a new pattern and bind it to a symbol like this:

 x = {Bool}

You can refer to another pattern within a pattern. Here is a pattern that matches a list of two Booleans:

 x = {Bool}
 y = {[x, x]}
 y == {[Bool, Bool]}

Inside patterns, the occurence of a symbol means, "bind whatever is here to this symbol for use later". For instance

Function definitions, pattern matching, and guards

todo

Guards are arbitrary other conditions on a partial function definition, which use the "if" keyword:

 y x f if y > 2 =
   x y div

Interfaces

todo

Different parts of the program may request different interfaces from the same value. For example, there may be a function that creates a binary tree, which supports the "tree" interface, and then passes it into a "map" function which requires the unordered list interface. The actual value which is created will support both interfaces, but the first function sees it only as a tree, and the second only as an unordered list ??todo??

patterns on graphs are the data interface, not the functional interface. Functional interface is a list of fn names and signatures. (umm.. what's the diff?, since __get is fn application? none fundamentally, i guess, but it seems diff)

a "behavior" completely determines the semantics of the value (although behaviors will almost always be unspecified, except where there is default types..)

interfaces have versions, but they must match their module versions

Type annotations

Type annotations tell the compiler that a certain variable must support a certain interface.

Examples: x{int} = 3

 x = 3{int}
 ["a"="apple" "b"="banana"]{node}
 ["apple" "banana"]{list}

Type tags

Type tages are hints to the compiler or interpreter about which interface implementation to use for a particular variable.

Type tages are written within type annotations following a colon following the interface type. Multiple type tags may be used, separated by commas. Boolean type tags are either present or absent; and parameterized type tags use the same keyword=value syntax as arc labels. Type tags which are earlier in the list have some amount of priority over those later in the list. Even after the implementation is selected, the chosen implementation has access to the type tags, so they can be used to specify optional implementation-level details such as the initial capacity of a resizable array. Example:

 {node: fastLookup, fastInsert, unordered, capacity=100}

this example specifies an object of type "node", and requests an implementation with the properties fastInsert and unordered, and sets the capacity to 100. Perhaps the compiler will choose a hash-table implementation for this node.

Type tags should never change the semantics of an object, only "implementation-level details" that may affect performance.

You may be thinking, "but I know exactly how I want this variable to be implemented, why can't I just say that?". Well, you can. Just make up a new type tag that says exactly what kind of implementation you want; "redBlackTree" or whatever.

Special type tags include the "myChoice" boolean tag, and the "implementation=" keyword tag.

Remote tagging

If you control the source code of an implementation, you can add tags to it there. But even if you do not, you can remotely "tag" an implementation with a boolean tag. You can also "untag", or remove existing tags:

 %tag moduleName:implementation myNewTagName1 myNewTagName2
 %untag moduleName:implementation tagToRemove1 tagToRemove2

Remote changes you make to tags only affect other modules if your module is imported using the "tags" or "all" modifiers to "import".

Directly choosing the implementation

If you need to constrain some variable to use a particular implementation, use a type tag of the form "implementation=typename". Don't do this, it's bad style. This is provided for debugging purposes. The preferred style is to create a new type tag to express whatever property that implementation has that you want; this way, others can create new implementations later which advertise your new tag. Other than "implementation:" type tags, import statements, and reflection on modules, there is no intentionally no way to refer to individual interface implementations.

Implementations of interfaces

In many cases, you will want to just write one implementation and as you add new functions to the implementation, you want them to be exported by the interface. So that you don't have to go and write the same thing twice, you can just use the declaration

 iface name auto

which automatically defines an interface of name "name" based on the functions defined in the current module -- except for functions whose name starts with '_', which are considered "private" and not included in the interface, assuming that the first character of the interface name is alphabetical. To define an interface which also includes functions whose name starts with '_', use the above but with a name that starts with the '_' character (todo: thx dana).

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
By default the compiler will give an error if an interface whose name starts with '_' is used. This is to make sure that  To make it compile, give the compiler the -exposeprivates flag.
=======
By default the compiler will give an error if an interface whose name starts with '_' is used. This is to make sure that it is clear that the convention is not to do this, and it is only for debugging and other weird situations. To make it compile, give the compiler the -exposeprivates flag.
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

There is a compiler command to produce a normal interface declaration for any interface generated using the "auto" keyword.

Terminators

In a language where data values of all types are represented as graphs, and containment of one object within another is represented as a link from some node of one object to some node of the other object, it can be hard to tell where one object ends and another begins.

For example, if one had a binary tree, in whose leaves were stored lists, some of which may have nested lists, how would one distinguish a list of two lists from an interior node of the tree? For instance, the graph might look like:

 [ [[5 3]] [[[3 1] 2]] [[3 2]] ]

is [[3 1] 2] an interior node or a leaf?

Note that this problem doesn't occur when you know beforehand the shape of the graph -- it only appears when you want to have general algorithms that apply to graphs of different depths and shapes.

One solution to this problem is to put leaf nodes inside a wrapper that identify them as such. In Jasper, a wrapper type is provided, called __terminators__. The wrapped values are called __terminal__ values, and the graph as a whole is said to be __terminated__. This terminology is used this because there are a number of functions in the standard library that recurse through a graph, do something with the terminal values, and then terminate the recursion, i.e. even if the terminal values are themselves nodes, the algorithm doesn't recurse into them and follow their arcs. A concise syntax is provided to make an expression terminal within a G-constructor:

  {{expr}}

Now we can disambiguate the previous example:

  [ [{{[5 3]}}] [[{{[3 1]}} 2]] [{{[3 2]}}] ]

is the G-constructor used to express the case where [[3 1] 2] is an interior node, and

  [ [{{[5 3]}}] [{{[[3 1] 2]}}] [{{[3 2]}}] ]

is the case where [[3 1] 2] is a leaf.

The terminator syntax is only available within G-constructors. The terminal value may be of any type. You cannot have a terminal value outside of a graph; if you fetch a terminal value, you just get the value, i.e. it is transparently unwrapped:

  [{{3}}].0 == 3

Flavored terminators

In some cases we may want to have a single graph which contains various different object boundaries. For example, perhaps we have TODO.

Jasper provides a way to attach an arbitary value to a terminator, called the terminator's __flavor__, with the idea being that the flavor tells you what kind of object is being terminated (or, to put it another way, what kind of terminator it is). We might have called this "labeled terminators", except that a terminal object may have a node label and may be the destination of a labeled edge, so we want to avoid confusion.

Functions in the core library which make use of terminators can be told to ignore all terminators except those of a certain flavor, or to ignore all terminators of a certain flavor. Functions are also provided to find all terminators of a given set of flavors and replace them with a different flavor (flavor map).

The flavor of a terminator is specified by a value, followed by a colon, in the terminator:

 {{flavor : terminal value}}

Terminatators within a flavor are of flavor nil.

Graph transformations

A convenient way to structurally transform a graph is to pattern match on it and then to construct a new graph based on the values bound to the pattern variables. This can be composed with two graph comprehensions (allowing only a map and a conditional) (one for the forward direction (for gets), and a simple map function for the reverse (for "__set"s); unfortunately, Jasper cannot calculate the inverse of a function) to yield a restricted way to transform both the graph's structure and the values within it. This is called a Jasper __graph transform__.

There is a convenient syntax for specifying a new data interface as a graph transform of an existing data interface: TODO

Significant whitespace

Like Python and Haskell, Jasper has significant whitespace. Like Haskell, this is optional.

A line in Jasper is either a physical line, terminated by \n, or a ';'-terminated line. These are the same in Jasper, except that '#' denotes a comment that runs until the end of the physical line.

An indented block in Jasper is either a physically indented block, that is, a contiguous group of nonempty physical lines all prefixed by at least certain number of spaces, (the indentation), or an explicitly delimited block, delimited by parentheses (in code; but see below), or by []s (in g-constructors). Tabs are interpreted as 4 spaces. Within a G-constructor, a line with only whitespace terminates a physically indented block, but a line with only a comment does not; within code, a physically indented block is terminated by another line without as much indentation. In both cases the end of file terminates the block.

Physical blocks are interpreted differently in ordinary code and inside g-constructors. Inside g-constructors, the contents of an indented block is interpreted as if it had []s around it. To open a G-constructor from within code, use a '[' as the last thing on the line; the G-constructor goes until the end of the indented block. Similarly, an indented block after a '

' as the last thing on a line is interpreted as the edges of that node, rather than as a child node. In other cases, an indented block within a G-constructor represents a child node of the containing node. For example
 x = [
     "apple"
     "banana"

is the same as

 x = ["apple" "banana"] 

and

 x = [
        'name="apple"
        'color="red"
        'price=40
 pr x.0.name

is the same as

 x = [['name="apple" 'color="red" 'price=40]]; pr x.0.name

and

 x = [
        'name="apple"
        'color="red"
        'price=40
        'name="banana"
        'color="yellow"
        'price=50
 pr x.1.name

is the same as

 x = [['name="apple" 'color="red" 'price=40] ['name="banana" 'color="yellow" 'price=50]]; pr x.1.name
 x = [
	appleState |
	    'transitions=
	        "0"=self "a"=self "c"=cherryState
	    'color="red"
        bananaState |
	    'transitions=
	        "a"=appleState
	    'color="yellow"
	cherryState |
	    'transitions=
 	        "0"=self "a"=appleState
	    'color="red"
 pr x..bananaState."a".'color #prints "red"

is the same as

 x = [[appleState | 'transitions=["0"=self "a"=self "c"=cherryState] 'color="red"] [bananaState | 'transitions= ["a"=appleState] 'color="yellow"] [cherryState | 'transitions=["0"=self "a"=appleState] 'color="red"]]; pr x..bananaState."a".'color

Inside

In ordinary code, a physical block is the same as

Some syntactic sugar

$$

$[]

[ $ $$ ]

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
== Metaprogramming ==

x<<Y>>
       x is construct name. $$ (expression eval) and '\<' -> '<' are done by Jasper and then Y is parsed by tokenized and parsed by construct and construct returns a value. Note that if Y is dynamically generated, construct will be compiled in and made available at runtime.

       ??construct may accept parameters by giving a regex in place of a static construct name, i.e. <flavor<<.

       mb constrain to just x/comma-sep-keyword-or-no-params<<
         </flavor<<
	 r/i<<
	 x/keyword=value,k2=v2<<
       
       keywords interpreted as strings by default (i.e. k=v -> "k"=v), and "k," with no v -> "'k=t", hence
         in r/i<<>> the args passed to r are "i"=t    
       if you want to pass in the values of symbols, use
         c = "i"; r/`c<<>>

%x Y   ??
       macro. x is macro name. Y is tokenized and parsed by Jasper and converted to Jasper Core (note: unshadowing is resolved here, among other things). x is a fn from Jasper Core to Jasper Core. Hygenic except for pronouns.

%begin x
Y
%end x
     preprocessor. x is construct name. Y is tokenized and parsed by construct; construct returns a string of valid Jasper which will replace Y in the source and be tokenized and parsed by Jasper later (returned string may itself contain metaprogramming directives including %begin). Should compiler provide anything about the rest of the code?

&&
	reflection, see below

eval
	Jasper compiler/interpreter which can perhaps access symbols in calling scope (mb only via references) in a typesafe way. if this is not present in the program source (after preprocessing :)) then compiler can elide the Jasper interpreter from compiled code.

other multi-stage programming/futures constructs (typesafe substitution, etc)

library fns for modular parts of the typechecking process


== Regexs ==

<pre>
string =~ r<<>>
</pre>

matches -> it


case insensitive:
<pre>
string =~ r/i<<>>
</pre>

>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Comments

./ /.


Interfaces

In some languages, there is a way to say that objects of a certain types support a list of function with specified signatures (and possibly semantics, although these are merely written down in natural language, not checked by the compiler). Examples are Java "interfaces" and Haskell "typeclasses" (although there are differences between Java interfaces and Haskell typeclasses), as well as "APIs". The analogous concept in Jasper is called a __function interface__.

In addition to function interfaces, there is another concept in Haskell called a __data interface__, which will be described below. An Jasper __interface__ consists of both a function interface and a data interface component (although either one may be empty).

Data interfaces

t = Tree([[1 2] [3 4]]) root / \ /\ /\ 1 2 3 4

t*leaflist looks like [1 2 3 4]

print(t*leaflist) [1 2 3 4]

def f(lst) = for i=0:len(lst) if lst[i] == 3: lst[i] = 4 return lst

y = t f(t*leaflist) == Tree([[1 2] [4 4]]) root / \ /\ /\ 1 2 4 4

but y still == Tree([[1 2] [3 4]])

print t*tree [[1 2] [3 4]]

print(f(t*leaflist)*tree) [[1 2] [3 4]]

f([1 2 3 4]) == [1 2 4 4]

so, data interfaces allow you to write functions that take a particular type of graph (like f in the example, which operates on a list of ints), but then use them to manipulate other types of objects, provided that the target object provides a data interface of the required type. the data interface specifies how to translate operations on the data interface value into operations on the target object itself.

  1. so, expressions of the form

so, the type of t*leaflist is list of ints -- however, although it can be manipulated like an ordinary value, t*leaflist is not an ordinary value, and operations on it correspond to operations on t. when you traverse the graph presented by t*leaflist, the result is dynamically generated by t's data interface, and when you apply functions to t*leaflist in order to create mutated versions of it, the mutated versions are actually values of type t generated by t's data interface according to which change you attempted to make in t*leaflist. the list of ints value that t*leaflist appears to present is really just a facade generated by t's data interface.

the burden is on the data interface to guarantee that the result of mutating t by way of mutations on t*leaflist leads to the expected changes in the illusory value t*leaflist (this is a law)

the list of ints value that t*leaflist presents is called the illusory data interface value. If a mutation of t*leaflist is made, the actual changes made to the value of t in order to create t' are opaque if t is an interface type.

<<<<<<< /root/website/lists/.unison.merge1-jasper.txt


== Self ==
Each lexical context provides a symbol that refers to itself, namely "self".

Example:

<pre>
0 f = 0
x f = x 1 - / self
->
0 f = 0
x f = x 1 - / f
</pre>

== Reflection ==
Reflection on any symbol is provided by prefixing the symbol by '&&', which refers to a read-only(?) reflection object.

A reflection object supports the following edge labels:

<pre>
'___uneval   	     some Jasper Core expression of the value bound to this symbol
  note: evaluating &&anything.___uneval is guaranteed to terminate
'___eval     	     ___uneval but with the additional guarantee that the expression has been fully evaluated
  note: the contents of ___eval itself may not be evaluated, however, until its evaluation is forced by printing it or whatever
'___type    	     a primitive expression of the type of the value bound to this symbol
'___symbolname	     the name of the symbol to which && was prepended in the Jasper source code
'___symbolfile	     the Jasper source code file in which this symbol was defined (may be "eval"!)
'___symbolfileline   the line of the Jasper source code  file in which this symbol was defined
'___origsrcexpr	     the expression in the original source code which defined this symbol
'___origsrctype	     the expression in the original source code which defined the type bound to this symbol
'___origsrctypefile
'___origsrctypelfileline
'___lexicalcontext   namespace reflection object
'___module	     module reflection object
</pre>

Note: if && never appears, then this information, and supporting functionality, can be compiled out; similarly if && is only bound to static symbols, info about most symbols can be compiled out.

Note: &&self may come in handy

||||||| /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
== Default wrapper type constructors ==
todo

data Tree a             = Leaf a | Branch (Tree a) (Tree a) 

wrapper Tree a             = Leaf a | Branch (Tree a) (Tree a) 

== Self ==
Each lexical context provides a symbol that refers to itself, namely "self".

Example:

<pre>
0 f = 0
x f = x 1 - / self
->
0 f = 0
x f = x 1 - / f
</pre>

== Reflection ==
Reflection on any symbol is provided by prefixing the symbol by '&&', which refers to a read-only(?) reflection object.

A reflection object supports the following edge labels:

<pre>
'___uneval   	     some Jasper Core expression of the value bound to this symbol
  note: evaluating &&anything.___uneval is guaranteed to terminate
'___eval     	     ___uneval but with the additional guarantee that the expression has been fully evaluated
  note: the contents of ___eval itself may not be evaluated, however, until its evaluation is forced by printing it or whatever
'___type    	     a primitive expression of the type of the value bound to this symbol
'___symbolname	     the name of the symbol to which && was prepended in the Jasper source code
'___symbolfile	     the Jasper source code file in which this symbol was defined (may be "eval"!)
'___symbolfileline   the line of the Jasper source code  file in which this symbol was defined
'___origsrcexpr	     the expression in the original source code which defined this symbol
'___origsrctype	     the expression in the original source code which defined the type bound to this symbol
'___origsrctypefile
'___origsrctypelfileline
'___lexicalcontext   namespace reflection object
'___module	     module reflection object
</pre>

Note: if && never appears, then this information, and supporting functionality, can be compiled out; similarly if && is only bound to static symbols, info about most symbols can be compiled out.

Note: &&self may come in handy

>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

Some library functions

assoc: takes an association table in this form:

$[[apple red] [banana yellow] [cherry red]]

and returns one in this form

$[apple=red banana=yellow cherry=red]

Some token operators

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
<pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

-- map recursively over terminated leaves -flavor- map recursively over terminated leaves of flavor "flavor", ignoring other terminators -!flavor- map recursively over terminated leaves of any flavor but "flavor", ignoring terminators of flavor "flavor"

--- map recursively over interior nodes and terminated leaves --flavor- map recursively over interior nodes and terminated leaves of flavor "flavor", ignoring other terminators --!flavor- map recursively over interior nodes and terminated leaves of any flavor but "flavor", ignoring terminators of flavor "flavor"


map recursively over interior nodes, stopping at terminators --flavor- map recursively over interior nodes, stopping at terminators of flavor "flavor", ignoring other terminators --!flavor- map recursively over interior nodes, stopping at terminators of any flavor but "flavor", ignoring terminators of flavor "flavor"

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt


=======
coordinatewise (like binary "map")
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

-/ foldr -\ foldl

scans? what else? repeats? self-repeats? flips?

<<<<<<< /root/.unison/backup/website/lists/.bak.1.jasper.txt
=======
</pre>
>>>>>>> /root/website/lists/.unison.merge2-jasper.txt

todo: convert term of any of a set of flavors to one flavor

note that the effects of foldr and foldl are in some senses "backwards" from their effects in Haskell, because Jasper is basically right-associative and Haskell is basically left-.

postfix:

' : strictify (strict in all arguments, and all functions called are strictified and forced eval'd (i think that's redundant, but whatever))

Some interfaces

bool

boolneg

partial order

set

ord

relation

(see table in 'Binary relations by property' http://en.wikipedia.org/wiki/Binary_relation for some others)

Some type tags

fastLookup

fastInsert

slowInsert

lowMemory

<<<<<<< /root/website/lists/.unison.merge1-jasper.txt

Some library functions

relations: closure

tree traversal algoritms:

tree algs:

sors algs: qsort

graph algorithms: min spanning tree, topo sort

network algorithms:

NP complete algs: 2SAT, 3SAT,

hofs:

terminators:

state machines:

other automata:

strings: regex,

matrices:

files:

net:


Project status

I am just writing down ideas. At this point, there is no timeframe to actually implement this. If i were to implement it, i would probaby write a Jasper core interpreter in Jasper core, then a Jasper interpreter in Jasper (this would give a chance to write something in the language to see which other language changes should be made), then a Jasper Core->Haskell compiler in Haskell (at this point Jasper Core could be compiled to Haskell and hence run, and the JC interpreter could be debugged), then a Jasper->Jasper Core compiler in Jasper Core l (at this point Jasper could be compiled to Haskell and hence run, and the full interpreter could be debugged), then a Jasper->Jasper Core compiler in Jasper, then a Jasper->Haskell compiler in Jasper (at this point the Haskell compiler code could be obsoleted and further changes to the language or the compilation to Haskell could be written in Jasper itself).

Design todos

/root/.unison/backup/website/lists/.bak.1.jasper.txt

Some library functions

relations: closure

tree traversal algoritms:

tree algs:

sors algs: qsort

graph algorithms: min spanning tree, topo sort,

the following basic graph ops direct producted with: arc, node; return mutated version of structure vs. return list; and, for nodes, only operate on terminal nodes, only operate on non-terminal nodes, operate on all; input to subfunction includes position in graph, or independent of position;

 label map
 map over arcs/nodes of label satisfying predicate
 delete arcs/nodes of label satisfying predicate
 fold (mutable, like map) over arcs/nodes of label satisfying predicate, with various tree/graph traversal choices (i.e. mutation by a "visitor"
 change or delete arcs/nodes of label satisfying predicate
 visit arcs/nodes and return arbitrarily changed graphs

network algorithms:

NP complete algs: 2SAT, 3SAT,

hofs: applyArgsAsDefault

terminators: flavor map (flavm), tdepth (terminate at depth)

state machines:

other automata:

strings: regex,

matrices:

files:

net:


Project status

I am just writing down ideas. At this point, there is no timeframe to actually implement this. If i were to implement it, i would probaby write a Jasper core interpreter in Jasper core, then a Jasper interpreter in Jasper (this would give a chance to write something in the language to see which other language changes should be made), then a Jasper Core->Haskell compiler in Haskell (at this point Jasper Core could be compiled to Haskell and hence run, and the JC interpreter could be debugged), then a Jasper->Jasper Core compiler in Jasper Core l (at this point Jasper could be compiled to Haskell and hence run, and the full interpreter could be debugged), then a Jasper->Jasper Core compiler in Jasper, then a Jasper->Haskell compiler in Jasper (at this point the Haskell compiler code could be obsoleted and further changes to the language or the compilation to Haskell could be written in Jasper itself).

Design todos

>>>>>>> /root/website/lists/.unison.merge2-jasper.txt
Branch (Tree a) (Tree a) " (http://www.haskell.org/tutorial/goodies.html) is not lost

Footnotes:

1.

2.

 mapfn(x) | list (if cond)

3. x.2

ex