notes-computer-jasper-jasperNotes1

mb give up on node labels and just have node labels be references but have have a mechanism to make namespaces into 1st class objects and to use them in the way i was using the supernode before

library fns to do the graph and category constructs in vaughan pratt's category theory handout

as nodes are fns, edge sets of vertices can be defined 'lazily'

homset: edges between given 2 vertices

slices:

1: -> [1 2 3 ...]

1:4 -> [1 2 3 4]

1:10:2 -> [1 3 5 7 9]

:3 -> [0 1 2 3]

: -> [0 1 2 3 ... ]

1:4.1 == 1

1:10.-1 == 10

1:10.[-1 2 -3] == [[1:10].-1 [1:10].2 [1:10].-3] == [10 3 8]

1:5.: == (1:5).(:) == [1 2 3 4 5]

./ note that no error is raised when indexing a graph node with a list of indicies, some of which are edge labels not present in the node /.

1:5.1:3 == (1:5).(1:3) == [2 3 4]

1:5.:3 == (1:5).(:3) == [1 2 3 4]

1:5.2: == (1:5).(2:) == [3 4 5]

[a==1

to achieve this, the default node

slicable: (int list) slicable = slicable

capitalize for types or ?x for pattern vars? eg ?: list: int (?x list) = ?x eg cap: List: Int (x List) = x eg both: Int (?x List) = ?x note: types that take args must always be fully applied in order to disambiguate b/t application of the parameterized type and application of an instance of the type to a value. fully parensethized too. you can always just use _:

(_ List) len = Int

behaviors are just null interfaces?? no, they are more like subinterfaces. well, mb thats ok.

in addition to mb, ' somehow denotes which edges are metadata

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)



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)


decided not to do this (instead, variadic):

*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))

can have row delimiters in linear lists for 2-D matrixes; not part of language, but convenient & std core lib -- mb '--' or '---'


(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; ez reading sounds good but it conflicts with the principal of currying and prevents the simplest way i can think of to give an function an argument as a keyword argument if it can handle them, but as positional otherwise

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

decided not to do this (hard to read):

When attached on either or both sides, loose-binding infix operators act like tight-infix ops on the attached side, but like loose-infix ops on the other side, and in addition have the effect of surrounding both the stuff on the unattached side, and the attached chain, with parens, e.g.

   (2 5 +) 5 - <=3 not
  -> 
   (((2 5 +) 5 -) <= 3) not

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)

decided not to do this:

  1. or, if *cond2 works (kinda lame): [a==1 "one"] [a==2 "two"] [f "other"] *cond2

(or rather, this isn't a part of the kernel that most ppl will be interested in)


decided not to do this:

Nil escaping

Sometimes you want to use nil to have some special meaning, but you also want to allow your client to put a nil in the values that they provide you with. In this case, you need to escape the client's nils so that you can distinguish them from your own. For this reason, the nesc and unnesc functions are provided. an (nil nesc != nil), but (nil nesc isnill == t). a "nill" is the type of nils and their escapes.

todo

mb a Maybe Maybe would be better here.... then your esc and unescaping is typechecked


decided not to do this: (no need for "produced-from" types)

so, the type inference system assigns to each lexical symbol two types, a "produced-from type", and a "used-as type". Both of these types are interfaces. an interface type may be composite, that is, a conjunction or disjunction of interfaces.

first, each symbol is assigned a produced-as and used-as type:

used-as-by-argument: The used-as type of a symbol which is the argument to a function is at least used-as type of the function's signature for that argument used-as-by-assignment source: The used-as type of a symbol which is assigned to another symbol is at least the used-as type of the other symbol

the used-as type of a symbol is the conjunction of all of the used-as types found by used-as-by-argument and used-as-by-assignment-source.

produced-from-by-constructor: the produced-from type of a constructor is the interface in which that constructor is found produced-from-by-assignment-target: the produced-from type of a symbol which is assigned the value of another symbol is at most the produced-from type of the other symbol

the produced-from type of a symbol is the disjunction of all of the produced-from types found by produced-from-by-assignment-target.


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


"component based programming where properties and metadata attributes were all first class in the language." -- http://www.computerworld.com.au/article/261958/-z_programming_languages_c

"[I also learnt to] design the language to be well-toolable. This does impact the language in subtle ways – you’ve got to make sure the syntax works well for having a background compiler, and statement completion. There are actually some languages, such as SQL, where it’s very hard to do meaningful statement completion as things sort of come in the wrong order. When you write your SELECT clause, you can’t tell what people are selecting from, or what they might select until after writing the FROM clause. There are things like that to keep in mind. " mb this argues against a backwards syntax??


^= pointer eq within 1 graph

pwd within 1 graph (what is this node's name via supernode?) pwd within tree (what is the path to this node from the root) pwd dynamic within acyclic (what is a path from A to B?)

list of all of a node's children by node.: (or node.*?)

filesystem as a graph "fs" (or "sys.fs"?), i.e. fileglob by "fs..cur.:" (or mb fs's "root" is always cur dir? so just fs.:, and fs..root for the root, and fs.parent for the parent.. need better notation for parent, mb fs.^) (ls == "fs.: "\n" intersperse concat pr" -- altho mb pr can concat itself, and intersperse w/ the right option, so "fs.: sep="\n" pr")

a . which is unattached on the left is short for "it.". at the beginning of the program, it. is fs.


for ipc: broadcast-only (read-only) message busses

any attached opening paired delimiter can mean to omit the other member? []... bad {}... good

some amount of whole program analysis is required in order to choose implementations unit types: what sort of typing can model the assignement of units (meters, seconds, etc) to variables? seems like the full type will be a direct product of the unit and the other stuff, i.e. this variable is both an integer and a unit. also, the number of bits to store the var is another ortho dimension; this variable is an 8-bit integer (that emits an error when it overflows), or a 16-bit integer (that emits an error when it overflows). what it does when it overflows, tho, is semantic; does it silently cycle, or does it raise an exception?

should we have a library providing constants to represent ontologically fundamental nouns, like time and space? i guess my preference would be, rather, include some semantic web stuff like good ways to refer to uris, and then the user can use whatever ontology they please

need to include good syntax for referring to propostions and proofs as first class objects (not just by constraint programming; the constraints (props) the proofs need to be first-class, too)

goal: to be a 'last language' in that its replacement will be written in it; language for writing languages; metaprogrogramming for the masses (incld static typing, laziness)

provide sequencing (non-laziness) partial ordering operators; these operators should carry guarantees about when things are released from memory

no "self", unlike in python also, "me" instead of "self"?

provide read-only references

starting n philosphers in haskell STM (from www-ps.informatik.uni-kiel.de/~fhu/projects/stm.pdf)

" import STM type Stick = TVar () takeStick :: Stick -> STM () takeStick s = do b <- readTVar s if b then writeTVar s False else retry putStick :: Stick -> STM () putStick s = writeTVar s True phil :: Int -> Stick -> Stick -> IO () phil n l r = do atomically $ do takeStick l takeStick r putStrLn (show n++". Phil is eating.") atomically $ do putStick l putStick r phil n l r startPhils :: Int -> IO () startPhils n = do sync <- newEmptyMVar ioSticks <- atomically $ do sticks <- mapM (const (newTVar True)) [1..n] return sticks mapM_ (\(l,r,i)->forkIO (phil eatings sync i l r)) (zip3 ioSticks (tail ioSticks) [1..n-1]) phil n (last ioSticks) (head ioSticks) "

types of annotations to provide: expression annotation (i.e. annotate a node in the AST), e-function (term?) annotations (i.e. annotate a token, which may be like annotating a node in the AST, or it may be like annotating something else)

sugar for lexically terminated g-constructors

in patterns, a version of "forall" that can specify that two nodes have the same number of children

for concurrency, a "gather" modifier (annotation) to fold ops, to perform "reduce" or "gather" operations over the results of many concurrent processes

jasper as preprocessor for perl, pyth, haskell, scheme, c, etc. jasper core, then jasper interp written in jasper core, with non-circular dependencies allowed between non-core constructs.

forking, files, pipes? streams? knowledge? opinions? probabikity? certainty of opinions? is there a way to work in bayes nets? supervised learning, clustering, dim reduction? linear programming? linear algebra? symbolic algebra?deduction? theorem ? induction? synchronized (locking) concurrency? vectorized ops? geometry? sets and multisets. shannon information? dynamic range, brightness. feedback, fourier, optimization, signals filters, evolutionary algs, hillclimbing, relational dbs, random vars

syntactic sugar for field initialization by constructor

constraint variable notation also used for random variables

f# quotes, used in LINQ, show how f# provides a uniform way to express computation within dsls

think if there is some redundancy between $$ and `, or b/t ? and ' (@ is distinct b/c it gets rid of the list constructors)

use "and" as the and composition operator for "chords", rather than "&"

matching a _ against bottom doesn't return an error in jasper; in fact, error only generated when evaluated err value, e.g. "a=err; b = 2; x y f = y; a b f" doesn't generate an error b/c even though the error is bound, it is not used

the android primitive UI elements provide inspiration for programming language primitives:

yes, home, mouse, back, no, menu, keyboard, touchscreen, camera, mic, speaker : true, home (root in a tree), spacial directionality and arrangement in data structures, back (up in a tree), false, meta attributes in data structures, string handling, OOP UI, peripherial I/O

common menu ops: undo, cut, copy, paste, open, save, save as, close, quit : undo, del, copy and bind x2,


it should be

take = 0 _ : [] _ [] : [] n x+xs : x,(n-1) xs take,+

this suggests a nice anonymous fn notation: fn x y : blah

and mb node names should also be delimited by =, rather than

if no inputs, colon not needed: a = 3


some notation to go ahead and strictly evaluate a list, or some portion of it at least. make strictness ez in jasper.

should we provide interface subtraction? i.e. pass this variable but hide some of its interfaces? this could be used to provide read-only references by doing S2 { (S type) - writable } = S incidentally, this notation also requires a way to say (S type) inside {}s. Sounds like that should be syntactic? in any case there should be an abbreviation for read-onlyness since it is so common; S2 %ro = S this is weird b/c normal expressions don't add or subtract interfaces -- the interfaces are statically inherent in the implementations, and normal expressions merely add requirements that BOTH sides of the expression support an interface. So {} isn't really the appropriate syntax. How about: S2 = S writable {-} or, for short, S2 = S %ro

and, if u need the type of something, use the operator "{}":

  type-of-S2 = S2 {}

a type is a pattern, a monotonic boolean expression with bound variables and quantifiers.

so, types (the requirements to be satisfied) are themselves monotonic; however, we can deny to promise that a variable satisfies them with the {-} operator. but we can't express a REQUIREMENT that a variable doesn't satisfy them (i.e. an assertion that a variable that we were given is readonly).

incidentally, this answer/question, promise/require duality should have syntactic support. like player/opponent. possibly like necessary/possible, obligation/right, etc. i guess this duality is most generally "someone else chooses/i choose". no, that's not quite it, is it? close though. anyhow, think about how to express minimax search and alpha-beta pruning and type promises/requirements, and mb learn modal logic.

spaces in types are like haskell's ->; = is not used


Things to decide on

Maybe vs. "nullable types", i.e. a value like nil, null, None, undefined which is a member of every type

I agree with GvR? that it's better for something to throw an exception than to return an unchecked None when, for example, a key is not found in a dictionary. I agree with this post that Haskell's Maybe is better than None: http://lukeplant.me.uk/blog/posts/null-pointers-vs-none-vs-maybe/

But Maybes clutter up code with all that fromJust, etc.

Perhaps use the "it" pronoun in conjunction with isJust as the bool interface? i.e.

 if x:
   return it
 else:
   raise "x was nothing!"

(i.e. "if x" called x's bool interface, which acts like isJust, and, in the case that isJust returns true, isJust also sets "it = fromJust x")

But then nested bool checks overwrite "it", which is annoying. How about a lightweight syntactic fromJust, along with the bool interface == isJust convention:

if x: return x' else: raise "x was nothing!"

mb the convention should be the other way around:

if x': return x else: raise "x' was nothing!"

hmm, i like that alot...

another example from that web page:

---

alpha renames a variable (from name to name') within an abstract syntax tree, unless there's a name collision:

alpha :: Name -> Name -> Term -> Maybe Term

alpha name name' (Variable var) = if var == name' then Nothing -- collision; name already used else if var == name then Just (Variable name') -- rename else Just (Variable name) -- keep old name

alpha name name' (Branch t1 t2) = do { t1' <- alpha name name' t1; t2' <- alpha name name' t2; return (Branch t1' t2'); }

alpha _ _ t = Just t

---

in Jasper, with the ' convention for Maybe wrapping:

alpha {Name Name Term (Term Mb)}

name name2 (var Variable) alpha = if var == name2 nil #collision; name already used

   if var == name
     (name2 Variable)' #rename
     
     (name Variable)' #keep old name

name name2 (t1 t2 Branch) alpha = t1_ = name name2 t1 alpha t2_ = name name2 t2 alpha t1_ t2_ Branch

_ _ t alpha = t'

---

or, if "if" is on the right:

alpha {Name Name Term (Term Mb)}

name name2 (var Variable) alpha = var == name2 if nil #collision; name already used

   var == name if
     (name2 Variable)' #rename
     
     (name Variable)' #keep old name

name name2 (t1 t2 Branch) alpha = t1_ = name name2 t1 alpha t2_ = name name2 t2 alpha t1_ t2_ Branch

_ _ t alpha = t'

---

or, if sequentially reducing levels of indentation can be used to help visually distinguish arguments on consecutive lines:

alpha {Name Name Term (Term Mb)}

name name2 (var Variable) alpha = var == name2 if nil #collision; name already used var == name if (name2 Variable)' #rename (name Variable)' #keep old name

name name2 (t1 t2 Branch) alpha = t1_ = name name2 t1 alpha t2_ = name name2 t2 alpha t1_ t2_ Branch

_ _ t alpha = t'


or, with nothing else on the line w/ the "if" (which, btw, has ultra-loose precedence):

alpha {Name Name Term (Term Mb)}

name name2 (var Variable) alpha = if var == name2 nil #collision; name already used if var == name (name2 Variable)' #rename (name Variable)' #keep old name

name name2 (t1 t2 Branch) alpha = t1_ = name name2 t1 alpha t2_ = name name2 t2 alpha t1_ t2_ Branch

_ _ t alpha = t'

--- nothing else on the line w/ the "if", and linebreaks distinguishing args:

alpha {Name Name Term (Term Mb)}

name name2 (var Variable) alpha = if var == name2

   nil  #collision; name already used
   if
     var == name
     (name2 Variable)' #rename
     
     (name Variable)' #keep old name

name name2 (t1 t2 Branch) alpha = t1_ = name name2 t1 alpha t2_ = name name2 t2 alpha t1_ t2_ Branch

_ _ t alpha = t'


with ? in place of "if":

alpha {Name Name Term (Term Mb)}

name name2 (var Variable) alpha = ? var == name2

   nil  #collision; name already used
   ?
     var == name
     (name2 Variable)' #rename
     
     (name Variable)' #keep old name

name name2 (t1 t2 Branch) alpha = t1_ = name name2 t1 alpha t2_ = name name2 t2 alpha t1_ t2_ Branch

_ _ t alpha = t'

---

some weaknesses:


Ideas

oop ideas

have some (syntactically/language supported -- you could do this in any case with a big long annoying switch statement) way for the program to dynamically choose which implementation is used for some constructor?

external process management

if jasper is to be a scripting language, it must be ez and concise to run external programs and communicate with them (a good test; it is easy to write a concise "expect" type thing in jasper?)

http://en.wikipedia.org/wiki/Categorical_list_of_programming_languages "Data-structured languages"

jasper is graph-based, which is a generalization of list-based. (& of table based). but make sure it has good support for array-based and stack-based stuff too.

misc ideas

iteration over a list with special instructions for the first and last element (good for i.e. printing comma'd lists!). inspired by falcon, example from falcon:

   for elem in saying
       >> elem
       formiddle: >> " "
       forlast: > "!"
   end

D's notation for vector ops looks useful: a[] = b[] + c[]

perhaps in jasper, a = b. + c. means elementwise +, and a = b. + c means map? naw, it's clearer to change the operator token as planned

D's "nothrow" functions

D's foreach has a concise way to ask for both the index and the value:

    foreach (i, arg; args)
        writefln("args[%d] = '%s'", i, arg);

still need to specify how graph assignment works so that multiple return values, and optional return values, work

lib support for deep copy/shallow copy distinction? but this is not functional... btw, cp is short for copy. mb shallow copy is accomplished by wrapping all items of the list in terminators (using "top" or "ttop" perhaps?)

predicate? notation from scheme sounds good. annoying to type, but ez to read. also, should we have fn! for fns with side-effects??? i'm thinking no...

C# disallows variable shadowing. mb a good idea...

should have inheritance for different behaviors within an interface? or only composition (=? delegation)? or how about inheritance-as-syntactic-sugar-for-composition: if you don't implement all functions in an interface, you can specify a delegate object and the other function calls are passed thru to it

i haven't yet specified the extensible typing of graph nodes

r, w for streams, what else (look at sockets?)

interp for: cli (stack based, static (but working on dlr)), parrot (register-based), jvm (stack-based). nekovm? avm2? compile to: haskell, mb llvm

read http://lambda-the-ultimate.org/node/3676#comment-52321

http://www.cowlark.com/2009-11-15-go/

"

Clojure easy to implement?

The basic language is easy to implement (and that doesn't make it less powerful), but the library (very fast persistent vectors/maps) and transactions? I'd say that there's more heavy lifting in Clojure than in Scala. By Jules Jacobs at Tue, 2008-12-30 15:51

Heavy lifting
login or register to post comments

Much of the heavy lifting in Scala has gone into its type checker - a problem that Clojure obviously doesn't have to face.

Rich has done some very terrific stuff with his library, and the Clojure community is beginning to contribute. But the Scala team and community are aware of the limitations of the current library and are working on it. For instance, the release a few months ago had new user contributed forms of maps similar to the Map and Vector implementations in Clojure. With the next release they've set the expectation to get a complete revamp of the collections library based on higher kinded typing which should mean a very rich set of reusable abstractions that are, along some dimensions, difficult to express in untyped languages. I expect great things from both teams and both communities in the coming year, but this isn't a thread about predictions. By James Iry at Tue, 2008-12-30 16:20

There is a lot of work on
login or register to post comments

There is a lot of work on the Scala library also (actors, transactions, high performance collections, ...), so I don't see your point. Basically, Scala's library is incredibly rich (and functional), and takes advantage of Scala's advanced features. "

compilation tools lib: words: LALR, LL{k}, Pratt-style, etc

http://perlgeek.de/en/article/mutable-grammar-for-perl-6

http://stackoverflow.com/questions/366998/good-resources-on-programming-language-design

"Also, if you have static types, you really need tuples to make functional programming work very well. Java lacks these." http://lambda-the-ultimate.org/node/3673#comment-52217

" Cross-cutting concerns

Security, transactions, monitoring/management, and session management. Code for these ends up scattered all over most enterprise applications, in ways that are both utterly stereotypical and easy to screw up. By Dave Griffith at Fri, 2009-11-06 23:33

"
login or register to post comments

" session management

This is indeed important, and we have a glimmer of good solutions with delimited continuations. By naasking at Sat, 2009-11-07 06:24

login or register to post comments"

" More Abstraction

Abstracting over patterns (pattern calculus, first-class patterns), abstracting over type structure (polytypism, polyvariadicity, more?), abstracting over execution (parallelism), abstracting over location (mobility), abstracting over bit-level data, and more use of partial evaluation and so less fear of using higher abstraction due to perceived performance degradation. That last point alone can bring significant improvements in conciseness. By naasking at Fri, 2009-11-06 18:30

" http://lambda-the-ultimate.org/node/3673#comment-52020
login or register to post comments

" . Haskell is seems to be settling on some high-level abstractions and their composition (monoids, arrows, monads, applicative, etc.). "

http://lambda-the-ultimate.org/node/3673#comment-52057

call-by-name?

call-by-reference?

call-by-value (isn't this just "strict"?)

case-insensitive except for capitalization

compiler command to translate to/from sig whitespace

D 2.0's "invariant" is like the default situation for Jasper; Jasper refs are like D's default situation for refs. http://www.digitalmars.com/d/2.0/accu-functional.pdf slides 15-21 describe invariant. basically, invariant is like a transitive (deep) const. notes: const is useful for dealing with fns involving refs; invariant(const) = const(invariant) = invariant; const(const) = const; implicit conversion from invariant refs and normal refs to const refs

D allows "automatic local" state within functional code (i.e. code whose inputs are invariant, and which are marked pure). kinda like what jasper is doing (except so far jasper doesn't actually allow imperative looping, but i have been thinking of adding something like it somehow).

mb : for list slicing like this: [2 3 4]:[0 2] == [2 4] [2 3 4 5]:0:2 == [2 3 4]:(0:2) == [2 3 4 5]:([0 1 2]) == [2 3 4] [2 3 4 5 6]:0:2:4 == [2 3 4 5 6]:(0:2:4) == [2 3 4 5 6]:(0:2:4) == [2 3 4 5 6]:[0 2 4] == [2 4 6]

mb would be clearer with

  [2 3 4 5 6]::0:2:4 == [2 3 4 5 6]::(0:2:4) == [2 3 4 5 6]::(0:2:4) == [2 3 4 5 6]::[0 2 4] == [2 4 6]

also, need to label nodes in parse tree; could use :key=val, or %key=val, e.g.

 z = (x.y %timeout=15msec)

for jasper, don't need haskell's default typeclass functions. also, don't need haskell's typeclass subclasses, exactly... implementations can assume another class, but the typeclass defn cannot.

icon "pulling out the subject" is interesting:

http://en.wikipedia.org/wiki/Icon_programming_language " s ? write(find("the"))

is a short form of the examples shown earlier. In this case the subject of the find function is placed outside the parameters in front of the question-mark. Icon functions are deliberately (as opposed to automatically) written to identify the subject in parameter lists and allow them to be pulled out in this fashion. "

generalize; a form of function composition that allows one to "save" the unspecified arguments from the inner function and allow them to become arguments of the composition. ie.

  1 [1 2 3] + map compose_but_save_arg_1 == [1 2 3] (1 +) map == [2 3 4]

more generally, give the composition a list of args to save:

  1 [1 2 3] + map [1] composeSave == [1 2 3] (1 +) map == [2 3 4]

or, provide sentinel values:

  1 [1 2 3] (SAVEME +) map composeSave == [1 2 3] (1 +) map == [2 3 4]

this may be hard w/o language support?? suggestion: use _ or ? or ^?:

  4 [1 2 3] (_ +) map == [1 2 3] (4 +) map == [5 6 7]
  4 [1 2 3] (? +) map == [1 2 3] (4 +) map == [5 6 7]
  4 [1 2 3] (^? +) map == [1 2 3] (4 +) map == [5 6 7]

also, should default args be saved (by default, ha ha)? if not by default, then mb by ^?*more

we already have generators b/c we have lazy lists

recursive strictify

strict syntax idea?:

  [2 3 4 5 6]::%now%0:2:4

rec strict syn:

  [2 3 4 5 6]::%NOW%0:2:4

or mb

  [2 3 4 5 6]::%nowr%0:2:4

also want a way to strictly pre-eval only part of the list, like, say, the first 100 elements.

so note that the %X% means to label the node to the left. it's like putting a ... X=t ... into the parse tree.

multiline: loose infix, = appended to the right of upper line, normal stuff to the left

the trash op can tell the runtime to forget its position in a lazy list, thereby saving memory at the cost of CPU time if the next element in that list is ever needed. as a profiling aid, in debug mode a list of kept of what was trashed and if it was used again (requiring recalculation)

list slices can be l-values. in fact, this should be extended to a generalization of graph assignment.

what should the indexing conventions be for list slices? we want it to be convenient to create a zero-length slice for use as an l-value, but we dont want it to be confusing. should 0:0 be nothing, and 0:1 be the first element of the list? this is how python does it. i always thought this was confusing, but i guess its the way to go if u want slice l-values.

caps 4 referencable values (nothing for types?) -- really, for non-referentially transparent values so, if a function contains a caps, it becomes monadic in the compiler, but w/o introducing an ordering. seq introduces an ordering.

should be "parsable w/o a symbol table"

can typecast as far as the data pattern goes -- essentially asserting that value matches some pattern

quotes: '(). can be used for F# style LINQ-ish stuff: '(4)

actually, use double quotes for code quotes, single quotes 4 strings:

  "(<<x.price*2 in table.row if x.color == 'red'>>)

actually, " can be applied directly to constructs, so

  cursor = "<<x.price*2 in table.row if x.color == 'red'>> db

principle: in DSLs, can use normal Jasper to express computation. example: can use list or graph comprehensions (querys) to query databases. example: can use ordinary Jasper fns as constraints, or as ops on random variables.

mb double quotes should have to surround.. no, ive got it -- when attached, they indicate that construct, but when unattached they must surround:

  "<<x.price*2 in table.row if x.color == 'red'>>
    ==
  " <<x.price*2 in table.row if x.color == 'red'>> "

current fn defn syntax is: plus = x y : x+y

so, can define constants without using colon: mapInc = (+1) map

and anon fns using just colon: mapInc = (x : x+1) map

"fn" keyword replaces $$, expands to 'i=n s=n z=n y=n x=n :'

types really are just sets of values (but what about types defined by a pattern?? i guess thats ok)

more misc

unique types (cannot be copied, only moved)

http://bartoszmilewski.wordpress.com/ has a good idea: " Actors in D

The D programming language with my proposed race-free type system could dramatically improve the safety of message passing. Race-free type system distinguishes between various types of sharing and enforces synchronization when necessary. For instance, since an Actor would be shared between threads, it would have to be declared shared. All objects inside a shared actor, including the mailbox, would automatically inherit the shared property. A shared message queue inside the mailbox could only store value types, unique types with move semantics, or reference types that are either immutable or are monitors (provide their own synchronization). These are exactly the types of messages that may be safely passed between actors. Notice that this is more than is allowed in Erlang (value types only) or Kilim (unique types only), but doesn’t include “dangerous” types that even Scala accepts (not to mention Java or C++). "

here's more on his idea: http://bartoszmilewski.wordpress.com/2009/05/26/race-free-multithreading/ http://bartoszmilewski.wordpress.com/2009/06/ and mb l8tr

his blog is also good to read 4 other concurrency thoughts

things like his race-free type system, and java's synchronized and volatile keywords, and timber's keywords, and "and" for chording, should mb be implementable as a library in Jasper. mb user keywords should be capped instead of state? naw

remember that supposedly-inconsequential state, like cache, is allowed (mb with some sort of override)

object methods should clearly distinguish "read-only" methods that don't modify the state of the object from others (mb read-only should just be functions?)

why have capital objects with state when you can already do referentially-transparent in-place mutation? mb caps are only needed when SOMEONE ELSE can modify the object's state when you aren't looking (or also, somewhat equivalently, when values are "entangled")?

statefulness vs. statelessness is a property of behaviors, not signatures

allow subclassing, with specifying specific implementation?

mb prefix with - for syntax tag? make _ for negation?!?

mb we should allow subclassing instead of just composition -- what subclassing allows you to do is to selectively override definitions of functions which take a value of the class as an argument. composition forces you to have the syntactic cruft of always referring to fields and methods within the composed object during your implementation of the overridden functions -- and also prohibits you from accessing "protected" fields. subclassing is dirtier, yes, because the actual code of the object is a mixture of the superclass's code and the subclass code, and those may be in two different places or even packages. however, why tie the programmer's hands? if all they want to do is to create a new class which is much like the old class except for a few tweaks, why make them go through the cruft of composition -- they should just be able to say, "same as that other code except for these tweaks", which is just what subclassing lets them do. still, we'll make composition-style "subclassing" easy by having the way to "inherit" ops by default --- note that the other reason for subclassing, i.e. subtyping, in Jasper will work w/ composition too, b/c it's just having a conjunction of interfaces.

extend nullable type ("maybe-ify") syntax to arbitrary type transformation (or just disjunctions?) what was my other idea for that? oh yeah, syntax to distingush "metadata" from non-metadata. sorta like graph terminators.

so can types (value sets) be operated upon by monotonic boolean ops on their characteristic function (basis set: and, or.. that is, set union and intersection)? do we need topological concepts here (infinite unions/intersections (which 1 was allowed again? only union?))

allow typecasting, esp for data patterns? also, note that all instances of dependency injection in http://www.martinfowler.com/articles/injection.html Fowler's article use typecasting to cast a returned component to an object of the correct type

?int as anonymous fn with anonymous argument:

  ?2 ?1 f == x2 x1 : x2 x1 f

(but ? alone doesn't, i.e. "lst ? map" isn't the way to do it, you want "lst ?1 map")

note that these sorts of expressions don't substitute as usual; "+1 (lst ?1 map)" doesn't mean "lst +1 map", it means "x : +1 (lst x map)"

mb ? is the more familiar substituting form? i.e. "+1 (lst ? map)" is "lst +1 map" after all?

mb if you have a stateful object, like "S", and you call an function on it using dot notation, like "S.f", then S is implicitly passed to f as "me". If the dot operator is applied again, S stays bound to "me" thru the end of the attached chain:

f = me "x" has if me.x++ me.x = 0

S = [] S.f ! S.x == 0

S = [] S.f.f ! S.x == 1

R = f

S = [] S.R.f # just to show that it's still "S" that is "me" ! S.x == 1

(in the above, I am using "!" at the beginning of a line to mean "assert"; my real preference is "ass", but some people might get mad at that. anyway, if assertions are used for typecasting, then they are magic in some way..)

(mb "!" at the beginning of the line is an assertion, a promise, and "?" at the beginning of the line is a question, a requirement?

no; the point is that these things are questions when they are reached, and then promises afterwards. just leave them as unadorned lines.)

mb omit "me" and just use "." (can still use "me" if you want the whole thing), or even nothing:

 f = me "x" has if
     .x++
   .x = 0

or even

 f = me "x" has if
     x++
   .x = 0

?? naw, i guess the former is better -- too hard to tell if x++ is a member variable or not

if you need "?.x", you'll just have to write that.

"quotient" operator: "/="

"repeat" (repmat, tile) operator: 'x'

replace <==> with cmp

perl6 has a convenient, loose infix version of haskell's "maybe" function: http://www.oreillynet.com/onlamp/blog/2007/12/yap6_operator_the_default_oper_1.html . we should too.

perl6's and and or junctions can be mimicked by views (what i used to call data interfaces). but this points out that we need a general way of adding generic view functionality to data structures, i.e. classes and/or mixins. i guess the same mechanism for providing functionality for stateful objects can be used for stateless ones? after all, the code for stateful mutation and pseudomutation of a struct's record is the same except that in the pseudo- case, writing to the destination forces the creation of a new value, whereas in the stateful case, it is merely in-place so are views just wrapped objects, then?

---

typed edges: don't forget typed edges. technically, we already support them via attributes on the reified edge nodes (i.e. edge.color = 'red), but need to make sure that libraries and basic syntax is friendly to typed edges. ideally, anything you can do w/r/t edge label, you can do w/r/t any edge attribute ("label" is just another attrib), and furthermore you can do with an arbitrary, passed-in function on edge attributes. should use typed edges to deal with meta-attributes and wrapped objects

   should things work by passing in functions to operate on nodes of a structure, or by adding attributes to that structure? the second is normally non-referentially transparent mutation, but mb we can unify these two things via pseudomutation -- i.e. rather than doing
      lst : 
        per_item_calculated_attributes = lst f1 map
        (lst per_item_calculated_attributes *zip) f2 filter // f3
   it seem more intuitive to do
      lst:
        lst f1 foreach // f2 filter // f3
      
   (where f1 mutates rather than just calculates)
   in other words, this suggests that we should be able to use wrapping to separate the added attributes from the original ones, using typed edges, like with meta-attributes
   
  an example in the Traits: Composable Units of Behaviour scg.unibe.ch/archive/papers/Scha03aTraits.pdf paper, section 3.3, shows how smalltalk has something to offer us w/r/t the syntax for  getters and setters:

center center: aPoint uparrow center center := aPoint radius radius: aNumber uparrow radius radius := aNumber

note how there is no need for __get and __set methods. instead the syntax used to define the getters and setters mirrors that used to get and to set.

however, perhaps this is to be interpreter in terms of messages. perhaps the idea is that, if you send the attribute an empty message, it answers with its current value. if you send it a new value, it sets itself to that value. this seems less desirable to me; i usually like unification/elegance, but unifying getting and setting into message passing seems like too much to me. it seems to me that getting and setting are sufficiently important to programming that these concept can be part of the language. and if they are part of the language, then we can do useful things like pseudomutation, read-only references, and the like, that rely on the language (or the runtime) knowing whether something is a get or a set (tho read-only refs is a special case of access control to methods).

also, syntactically it seems like a good idea to make functions of fixed arity, even if they can be polymorphic in the types accepted by each slot.

design decision: get, set are concepts included in the language containers is a concept included in the language

hmm, i guess __get, __set on graphs was already an "object" or struct or something, right? but it seems single-dispatch, whereas i thought i liked multiple-dispatch. i guess that if you can make functions attributes of objects, then you basically can do single-dispatch methods.

if you want prototypes rather than classes, but you don't want nullable types, then how does that work? b/c when you copy the prototype, it is "uninitialized" until you call a constructor, right? like, a "circle" object wouldn't have a radius, yet. are they just prototypes wrapped by an "unconstructed" wrapper (i.e. a maybe)? but you have to have access to the constructor. so is it not a maybe, but something different, with an "init" method? arg. mb just use classes :[. remember that part of the point of classes is to make sure that it is clear when objects (structs) are in an initialized state (i.e. they are after the constructor has been called). mb generalize this to a notion of objects with state? mb related to wrappers, meta-attributes, typed edges, etc?

the stuff about how to resolve method conflicts with inheritance is the same problem as how to resolve name conflicts when merging graphs, and the same machinery should be provided. in fact, the traits in Traits: Composable Units of Behaviour scg.unibe.ch/archive/papers/Scha03aTraits.pdf paper induce a dependency graph, which also shows the method conflicts and their resolution; this graph could be explicitly manipulated in Jasper if something like traits were used.

note that, if traits are sets of methods attached as attributes to structs, then inheritance is merging structs, and conflicts are edge label conflicts

in fact, if two edges with the same label are not allowed, then the node is a namespace, and merging such nodes == dealing with method conflicts in inheritence == merging namespaces == merging two nodes with uniquely labeled edges, and resulting with uniquely labeled edges

traits seem to be like mixins, but with a different merge strategy (aliases, rather than 'the rightmost (last) node to be merged overrides the previous nodes', which seems to be the mixin doctrine). and both are like multiple inheritance on prototypes, except: other forms of multiple inheritance either require you to explicitly name the class of the super when you refer to inherited stuff (C++) -- and this breaks the flattening property, as discussed in Traits: Composable Units of Behaviour scg.unibe.ch/archive/papers/Scha03aTraits.pdf; or they require you to rename stuff in the super (Eiffel?), but this breaks modularity, b/c other guys that use the same super are affected; or they put a total ordering over the parents (Python), but this is confusing. oh, and also: traits cant define or (directly) access state in jasper, since any state can be turned into a getter, the prohibition on accessing state directly is irrelevant

i guess the relation of namespaces to graph nodes in general is the same as the relation of function to binary relations

metadata/typed links: i guess one could "flatten" a node, i.e. take a node A such that A.0 = B, and allow A.x to refer to B.x, unless there is an x edge from A. the edges which are really B's could be distinguished by an edge type. one could extend this to flattening a tree of nodes into A, with the node type distinguishing some property of the path from A to B.

the flattening and the views brings up the notion of an "internal reference" -- that is, a reference that only refers to something else in this value, rather than linking to a value which can be referred to by two variables at once. e.g. if A.c refers to A.color, but "B = A.c" does not link variables B and A, then A.c is an internal ref (internal to A). todo (views)

junctions could be done as a wrapper that generically: * intercepts any function that returns a value of the type of the underlying value, and makes it return a junction instead (where the op is done in parallel for ea. val in the array) * intercepts any function that returns something else and applies some reduce function to the junction to get a single result value out of the junction, then passes this result as if it were the value of the junction so we need this sort of "generic intercept"

if refs used "^" rather than "&" than can use same char to create and to mark refs:

  a = x            ./ a is a copy of x /.
  ^a_ref = a ^     ./ copy a, and create a_ref, and point a_ref to the copy of a /.
  ^b_ref = ^a_ref  ./ both a_ref and b_ref point to the same place /.
  c = b^ref        ./ copy the value pointed to by b^ref into c /.

otoh, mb you dont need the a ^ b/c assigning a value to a ref is illegal anyways:

  a = x            ./ a is a copy of x /.
  ^a_ref = a       ./ copy a, and create a_ref, and point a_ref to the copy of a /.
  ^b_ref = ^a_ref  ./ both a_ref and b_ref point to the same place /.
  c = b^ref        ./ copy the value pointed to by b^ref into c /.

^ seem preferable to & b/c attached & already has a meaning (partially applied logical AND). this would mean ditching "unshadow", though, and finding another char for "parent" inside graph constructors

streams/channels: in addition to a program-wide stdout, stdin, stderr, stdprogress, stdmsg, stdwarn, etc, there should be intra-program versions of these. also, should be able to create streams over arbitrary types, not just characters, and to convert these to/from streams of other types (like char) easily (i.e. by giving/using the toStr function for an object)

---

notes on traits

flattening property

---

map 'symbols to URIs (in ontologies); i.e. color = 'red


URIs, semantic web-ish ontological support. ie categories like time and space not in language, but easily imported from external, standard ontologies via URI support.


difference b/t uninitialized & initialized objects could be captured by types with constants in pattern match rather than by class vs. object


mb "layers"; a "meta" operator that you can apply to symbols (in fact, to anything, i guess) that then looks them up in the next layer up. if you enumerate all the entries in a node, you only get the layer you asked for. i.e.

g = $[name=apple color=red] g.("name" meta) = "example g" == "name" meta g g sz = 2 g meta sz = 1

of course, instead of "meta", we should have a token operator. mb just reuse ' ?

g = $[name=apple color=red] g.'"name" = "example g" == '"name" meta g g sz = 2 g meta sz = 1

but then cant have symbols be dict keys? hmm, mb thats not so bad -- mb they SHOULD be meta? anyhow, why would you want to use local symbols to lookup stuff? hmmm mb u would...

hmm, also, should provide parallel (direct producty) layer ops...


switch " and '

use normal namespace instead of putting namespaces in supernodes

should have just one ! for mutation b/c it will be common -- use ~ for not

need to distinguish sz of lists from total dict sz

i guess could make it illegal to partially apply commutative binary ops by putting them infix attached on the right -- that opens up *,+,&,

for postfix token ops

i guess the "meta" idea is just saying that arcs are typed, that by default only the vanilla arcs are in play, and that "meta" converts a vanilla-type value to a meta-type one. "vanilla" can be denoted by 0, and "meta" layer 1 by 1. parallel (direct producty) layer ops just means that the user can use other arc types, too. now, do we really want each value to in addition have an arc type (flavor), or do we want to just operate on the node? i.e. instead of

g = $[name=apple color=red] g.("name" meta) = "example g" == "name" meta g g sz = 2 g meta sz = 1

we could do

g = $[name=apple color=red] (g meta)."name" unmeta = "example g" g sz = 2 g meta sz = 1

where "g meta" is a view of g in which the vanilla arcs are not present, and the meta-1 arcs have become vanilla

or for short,

g = $[name=apple color=red] g'."name" = "example g" g sz = 2 g' sz = 1

note that this conflicts with the proposal for a lightweight mb notation -- unless we decide to conflate these two shortcuts on purpose, which may be a good idea.

note: mb should have x'.0 == x

note that the types of arcs should be able to form a faceted classification and multiple inheritance subclassing (see also that other kr inheritance idea)


if types are values, and types' extend to sets of values, then what about russel's paradox? russel's paradox prevents the set of all sets from being a set, but wouldn't an analogous argument prevent the type of types from being a value? no, b/c the types don't quite obey the axioms of set theory; the http://en.wikipedia.org/wiki/Axiom_schema_of_specification , which lets you construct the subset of a set that obeys some property (like the "filter" function) doesn't hold here, b/c if you tried to construct the set in russel's paradox, the program wouldn't halt when evaluating the construction:

  the set of all sets that don't have themselves as members

if you created this set in a program, and then asked it if it was a member of itself, it would check this by calling the condition "not(member(x, x))" -- which, in turn, would call the same condition to evaluate member(x, x) -- so it would loop infinitely.

so, instead of allowing all formulas, the condition should be restricted to formulas that don't reference the current set, either directly or indirectly (technically, this is too strong; you can reference the current set provided you always halt.. for example, you could call yourself and pass a parameter that is decremented by 1 each time).


in jasper, mb:

composition and mixins/traits/roles (what about delegation, late binding to self/prototypes?) for code reuse

interface dependency (like inheritance) for taxonomy

interface for encapsulation

interfaces for polymorphism (interface dependencies for ad-hoc, parameterized type vars for parametric?)

  views? behaviors?

jasper vs. gentle intro to haskell

5 typeclasses

http://www.haskell.org/tutorial/classes.html

note: yes, parametric polymorphism is quantifying over all types, typeclasses are quantifying over only certain types. also, however, parametric polymorphism provides a specific role for one type in the construction of another types (i.e. in a vector of ints, Int is fulfilling the role of "what is it a vector of?") -- i.e. a structuring mechanism. also, in type classes the behavior of the interface fns can be defined differently for each implementation.

note that "Type applications are written in the same manner as function applications. The type T a b is parsed as (T a) b."

note: i guess we need kinds in jasper

6.1 newtypes yes, jasper needs something like this

6.2 field names in a manner of speaking; in jasper, fields of types can be inferred via structural typing, so no "data" decl is needed. since graph nodes are like dicts, not just lists, the fields (arcs) are already nameable. all fields are already like python "properties", that is, by default accessed by default accessors, but these accessors can be overridden.

instead of having absent fields be undefined, the Maybe-like ' operator is used

like haskell, applying an update to an object is non-destructive (referentially transparent) by default

the stuff about field names generalizing to multiple constructors does not apply to jasper, since jasper uses disjunctive interface types rather than disjunctive constructiors for abstract data types

field labels are not functions, they are just values, so the same field label can be used for more than one data type in scope.

in haskell, field labels are just syntactic sugar, but in jasper, they are a fundamental part of nodes

6.3 strict data constructors

haskell's syntax: data RealFloat? a => Complex a = !a :+ !a

note: good example of laziness; a list with one non-terminating or erroneous element may still be used, provided that element is not read

jasper probably wants strictness flags for fields (arcs). mb this can be accomplished by wrapping the __get or __set fn corresponding to that arc?

haskell has no syntactic way similar to strictness flags to mark certain argument slots of a fn as being strict; you have to use seq or !$. jasper will have one.

gentle intro says " It is difficult to present exact guidelines for the use of strictness flags. They should be used with caution: laziness is one of the fundamental properties of Haskell and adding strictness flags may lead to hard to find infinite loops or have other unexpected consequences. " -- since this has been written, have such more guidelines been developed? gentle intro said:

" There are a number of situations where it may be appropriate to use strictness flags:

also, j should have a by-value way to denote strictness i.e. a way to take an ordinary lazy list and make it a strict list, without reimplementing it. this should include shallow strictness and deep strictness.


"...The Google thread does present a legitimate speed argument in that all these dictionary lookups prevent inlining of functions. This isn't an issue in Haskell, where CallByNeed? prevents inlining anyway." --- http://c2.com/cgi/wiki?ManifestTypingConsideredGood

crikey, he's right. we need a way to specify that we don't care if a function is strict or lazy, so that the compiler can choose to inline it or whatever. but then what if someone passes in an infinite list? well, the list is lazy, not the fn.

"Don't think so. But the truth is that some type inferencing algorithm is way overboard for the efficient understanding and tractability by the programmer, especially in the presence of parametric polymorphism and type classes (i.e. not even real polymorphism yet, since DynamicTyping? advocates would laugh their butts off when you can't store ints and floats in a list because the type class Num is not actually a real type. When and if you solve this other problem, I guess a good PhD? test could be "can you write a Haskell program that will type check the first time?". Which would not be bad in and of itself, except that it's cracking a nut with a sledgehammer. " is this true in haskell? i don't think so. but jeez, definitely you use can interface types as the types of values in lists in jasper.

"­ Through increased uniformity, stronger guarantees, and facilities supportive of novices (there will always be more novices than experts) " -- http://www.research.att.com/~bs/C++0x_keynote.pdf

"· Remove embarrassments ­ Frequent questions, frequent novice errors " -- http://www.research.att.com/~bs/C++0x_keynote.pdf

" Standard library ideas · Elements of standard platform ­ set of resource handles supporting "resource acquisition is initialization" ­ directories, TCP/IP, advanced I/O (async, multiplex, memory map), ... · Make the standard library central to bindings to other systems ­ CORBA, SQL, ... · Distributed computing ­ XTI (eXtended Type Information) ­ Threads ­ Remote invocation (incl. Async) ­ Remote instantiation, name server interface · Add a few "general utility" facilities ­ Hash_map ­ Pattern matching ­ Properties ­ Constraints checking " -- http://www.research.att.com/~bs/C++0x_keynote.pdf

"the name "length" is reserved for lists (aka the type [a]). Now one may want to introduce it's own kinds of lists, say a doubly linked list, or a list backed by an array.Of course the newly introduced types will also need a "length" operator, but since nobody at the DesignPhase? of Haskell foresaw the need for an interface (aka type class) that defines the length type, then the new guy who writes the doubly linked list will not have an interface to adhere to and his newly defined name will class with the other defined name. Of course, modules to the rescue, i.e. one will be addressed as Prelude.length, and another one will be addressed by DoubleList??.length. So we're back to square one (ML). Another instance is where different type classes define the same names for operators, to resolve the potential client of both will disambiguate by using module name. " http://c2.com/cgi/wiki?ManifestTypingConsideredGood this is the problem that the prohibition on consumer specification of implementation types in jasper is supposed to solve

"The assertion was made above that type classes and Haskell type system solve all the problems with type inference without suffering the drawbacks of ML. Actually, Haskell's type system is quite a beast, and it's inherent complexity in addressing simple things is sufficient of a drawback. However, after a brief excursion into Haskell, here's the problem with TypeClasses?: they are not first class in the type system. They are very different beasts.

For example under Haskell there's no way to create a list with the following content: [1,"string"] although both elements implement the "Show" interface (speaking in the language of Java mortals), i.e. their types are instances of "Show" and provide the function "show : a -> [Char]" (roughly the equivalent of Java's toString()).

As always, Haskell continues to evolve. GHC 6.6 will support this (or the 6.5 development snapshots, if you are feeling adventurous), as long as you help it along a bit by declaring the type of the list [forall a . Show a => a]. A bigger problem is that given a list with a type like this, *all* you can do is call methods of class Show (and superclasses). A list of things you can do nothing with but convert to strings is not much more useful that just having a list of strings in the first place. There is a class Typeable you could add to partially get around the restriction, but it's still pretty messy" http://c2.com/cgi/wiki?ManifestTypingConsideredGood

in jasper, it will be simple to create a list of showables. or, you could use disjunctive types and create a type of "Num or Str" and then you can use pattern binding conditionals to dispatch based on which it is


could use asserts to assert type matches as well as for runtime checks

mb need to have some equivalent of java final for base types (string, etc)? but mb should be final METHODS rather than TYPES to prevent this prob:

"

Imagine you have an API written by someone else. You don't have the right (or access or source code) to change it. You have to live with it.

You have a method called on a Logger object called log_message(). It takes a single argument -- a String. Any String you pass to the logger gets logged to the appropriate place.

Suppose you have an object which represents a Customer -- a name, an address, some notes. Suppose you want to log the relevant customer information. Easy, right? Just produce a String from the Customer and send that String to the log_message() method.

Except suppose that the library's version of String supports onoe encoding and the String produced by the Customer object is an incompatible encoding... or this or that or you just object to the two-step boilerplate code that makes you manually stringify your Customer objects when they already know how to stringify themselves.

A better approach is to change the log_message() signature to decouple it from the concrete String class to an interface which means "Anything which implements this interface produces a String when I call its stringify() method." " --- http://www.modernperlbooks.com/mt/2009/05/

bounded generics?


i agree with Simionato that having to deal with method resolution order sucks, which rules out multiple inheritance and mixins, and leaves only traits. i agree with Simionato that cluttering namespaces with multiple inheritance or mixins or traits sucks, but i think this should be dealt with by programmer style/taste, not by the language. i'm not sure if i agree with him that adding more type cases to multiple dispatch functions is better than cluttering the object namespace; you have less namespace clutter but more nonlocality of code -- unless you accept that multiple dispatch functions should be inherently nonlocal?

actually, i want traits but with the ability for a trait to contain private local methods that aren't exported (i.e. its own namespace)


C++ distinguishes between stack and heap -allocated things. jasper doesn't (although mb you can use "tags" on the ST somehow to accomplish this)


one way to improve jasper: find a "rosetta stone" comparison between the best way to do something in jasper, and a way to do the same thing in another language, where the other language's way is more concise or easier to read or more general or more "elegant" than jasper's


the thing with multiple dispatch is, since each variable and value may belong to multiple types, often there would be more than one multiple dispatch rule that applies. luckily, at least this would be detected at compile time. suggest a requirement for explicit disambiguation. note that this is no worse than dispatching off typeclasses in haskell (actually, is that allowed in haskell?) maybe mutually-exclusive types should be allowed after all? (shiver; this would break the positivity of the type system)

one good thing about multiple dispatch (like dynamic prototypes) is that you can easily see how to "dynamize" it, i.e. the handlers for different cases can be registered or reregistered at runtime, allowing a component-y thing.


in most programming languages, types do double duty: they are a name for the actual representation or implementation of a data structure, and possibly associated operations; and they define the interface for interacting with that data structure. in jasper, these are separated; except for debugging, when you are using a data structure, you never specify which specific representation you want, only which interface you want.

--- mb use the dash ('-') as list append operator, and + as concat? .+ and .- for map + and - over the list. but then what if you want to map append or concat? hmm.. i guess different identifiers are needed. how about ++ for concat and -- for append?

---

unlike php, should not need to preface calls to static fn in same class with class reference


php's []

php's common_user, other common_s

---


"Choosing the best notation is the entire problem of programming language design, and this problem is neither mathematical nor scientific. A programming language is a user interface for programmers, and if you can reduce UI design to math, science, or any formal process, call Apple, not me." -- http://www.cppblog.com/cfmonkey/archive/2008/07/31/57671.html


python, with scipy, has structual assignment (pattern matching):

In [29]: b = [[1,2], [3,4]]

In [30]: b = array(b)

In [31]: c = b + 1

In [32]: (b[1,:], c[1,:]) = (a,a)

In [33]: b Out[33]: array([[1, 2], [1, 2]])

In [34]: c Out[34]: array([[2, 3], [1, 2]])

---

mb should just let the user use () and [] both for parens (but each one only matches itself), to increase readability when you have lots of parens

can't do this if the results start out as empty lists in python:

    (gradient_angle_images[imageIdx], normalized_gradient_magnitude_images[imageIdx], blurred_normalized_images[imageIdx])  = process_image_for_cosine_similarity(images[imageIdx], blurring_amount_in_pixels);

can do this but it's harder to read:

    zipAppend((gradient_angle_images, normalized_gradient_magnitude_images, blurred_normalized_images), process_image_for_cosine_similarity(image, blurring_amount_in_pixels))

def zipAppend(lists, newItems): if len(newItems) != len(lists): raise("zipAppend requires two arguments of the same length") for i=range(len(newItems)): lists[i].append(newItems[i])

it's nice how you can multiply return arguments in octave and then silently ignore them by only taking the first few ones. in python, you can return a tuple, but then the caller can't silently drop args.

" Kay's original vision for object-oriented programming -- or OOP, which he pronounces like “oops” without the “s”—was grander than just the idea of organizing code into reusable routines. Kay-style OOP aimed for a total rethinking of one foundation of our software universe: today's near-universal separation of program from data, procedural code from stored information. Instead, imagine a system in which the information and the code needed to interpret or manipulate it travel together in one bundle, like a cell traveling with its packet of DNA. ... "In computer terms, Smalltalk is a recursion on the notion of the computer itself. Instead of dividing "computer stuff" into things each less strong than the whole – like data structures, procedures, and functions … – each Smalltalk object is a recursion on the entire possibilities of the computer. Thus, its semantics are a bit like having thousands and thousands of computers all hooked together by a very fast network" ... The result is what Kay call "a more biological scheme of protected universal cells interacting only through messages that could mimic any desired behavior" " -- dreaming in code, 288-289


http://www.stanford.edu/class/ee380/


flat-out closures vs. classes:

def imss(data, detailplot_callback = None, xs=None, ys=None, labels=None): fig1 = pylab.figure() ax = pylab.imshow(data, figure=fig1) fig2 = pylab.figure()

  def ca(fig2, data, xx, yy):
    fig2.clf()
    if numpy.ndim(ys[yy, xx]):
      pylab.plot(ys[yy, xx], figure=fig2)
    if labels is not None:
      fig2.suptitle(labels[yy, xx])
  if (not detailplot_callback) and (ys != None) and (xs != None):
    detailplot_callback = lambda ax, data, xx, yy: ax.plot(xs[xx*numpy.shape(xs)[1]+yy],ys[xx*numpy.shape(ys)[1]+yy])
    
  if (not detailplot_callback) and (ys != None):
    detailplot_callback = ca
      #lambda ax, data, xx, yy: ax.plot(ys[round(xx)*numpy.shape(ys)[1]+round(yy)])
    ####detailplot_callback = lambda ax, data, xx, yy: (sys.stderr.write(`xx` + `numpy.shape(ys)` + `yy` + '\n ' + `xx*numpy.shape(ys)[1]+yy` + '\n'))
  def show_hoverVal(event):
      if event.xdata and event.ydata:
        #print `event.xdata`
        #print `event.ydata`
        try:
          event.canvas.toolbar.set_message('%d, %d: %f' % (numpy.round(event.ydata), numpy.round(event.xdata), data[numpy.round(event.ydata), numpy.round(event.xdata)]))
          if detailplot_callback:
            #pass
            #ax = event.canvas.figure.add_detailplot(1,1,1)
            detailplot_callback(fig2, data, numpy.round(event.xdata), numpy.round(event.ydata))
        except IndexError:
          event.canvas.toolbar.set_message('')
      else:
        event.canvas.toolbar.set_message('')
       
  ax.figure.canvas.mpl_connect('motion_notify_event', show_hoverVal)
  
  return ax

vs callable classes:

class Detailplot(object): def __init__(self, ys, xs=None, labels=None): self.ys = ys self.xs = xs self.labels = labels

  def __call__(self, fig, data, xx, yy):
    fig.clf()
    if numpy.ndim(self.ys[yy, xx]):
      pylab.plot(self.ys[yy, xx], figure=fig)
    if self.labels is not None:
      fig.suptitle(self.labels[yy, xx])

def imss(data, detailplot_callback = None, xs=None, ys=None, labels=None): fig1 = pylab.figure() ax = pylab.imshow(data, figure=fig1) fig2 = pylab.figure()

  if (not detailplot_callback) and (ys != None) and (xs != None):
    detailplot_callback = lambda ax, data, xx, yy: ax.plot(xs[xx*numpy.shape(xs)[1]+yy],ys[xx*numpy.shape(ys)[1]+yy])
    
  if (not detailplot_callback) and (ys != None):
    detailplot_callback = Detailplot(ys,xs,labels)
      #lambda ax, data, xx, yy: ax.plot(ys[round(xx)*numpy.shape(ys)[1]+round(yy)])
    ####detailplot_callback = lambda ax, data, xx, yy: (sys.stderr.write(`xx` + `numpy.shape(ys)` + `yy` + '\n ' + `xx*numpy.shape(ys)[1]+yy` + '\n'))
  def show_hoverVal(event):
      if event.xdata and event.ydata:
        #print `event.xdata`
        #print `event.ydata`
        try:
          event.canvas.toolbar.set_message('%d, %d: %f' % (numpy.round(event.ydata), numpy.round(event.xdata), data[numpy.round(event.ydata), numpy.round(event.xdata)]))
          if detailplot_callback:
            #pass
            #ax = event.canvas.figure.add_detailplot(1,1,1)
            detailplot_callback(fig2, data, numpy.round(event.xdata), numpy.round(event.ydata))
        except IndexError:
          event.canvas.toolbar.set_message('')
      else:
        event.canvas.toolbar.set_message('')
       
  ax.figure.canvas.mpl_connect('motion_notify_event', show_hoverVal)
  
  return ax

seems to me that callable classes are clearer, and have the benefit of being subclassable, although for simple cases closures require slightly less typing...

if python were made a bit more concise, we could have made most of the extra junk in the callable class (i.e. the initializers) go away...

(also, in the above example, i'm not sure that the latter is really a closure; does, e.g., fig2 get shared b/t multiple instances?)

---

ez way to:

debug log upon each entrance and exit to a fn, or to a fn within certain packages/module files, logging all arguments passed/returned

trace (log every line)

---

(gradient_angle_images, normalized_gradient_magnitude_images, blurred_normalized_images) = process_dataset_for_cosine_similarity(images, blurring_amount_in_pixels)

fn defn form

---

often in Python you pass default keyword args down the line:

def clusterPlot(linkage_result, criterion='distance', step=.02, thresh=1, keywords): clusterPlotKeyHandler = ClusterPlotKeyHandler?(linkage_result, criterion=criterion, step=step,thresh=thresh)

is there a quicker way? this is particularly annoying when you want to add a new argument and you have to pass it all the way down; you have to modify the signature of each fn in the stack

also, luckily it's intuitive to pass varargs that way:

def clusterPlot(linkage_result, criterion='distance', step=.02, thresh=1, keywords): clusterPlotKeyHandler = ClusterPlotKeyHandler?(linkage_result, criterion=criterion, step=step,thresh=thresh, keywords )

instead of doing,

  def __init__(self, linkage_result, D_valid, criterion='maxclust', step=1, initThresh=2, imshow_origin='lower', title='', postprocessFn=None, order='F', **keywords ):
      self.linkage_result = linkage_result
      self.criterion=criterion
      self.thresh = initThresh
      self.step = step
      self.D_valid = D_valid
      self.keywords = keywords
      self.imshow_origin = imshow_origin
      self.title = title
      self.order = order
      self.postprocessFn = postprocessFn

, just have an object-local variable scope for pete's sake!

in python:

for i in range(10)

why not just:

for i in 10


it's important to have zip and multiple assignment available in list comprehensions:

[matching[flatclustering] for matching, flatclustering in zip(matchings, flatclusterings)]

having both fns and members leads to awkwardness:

    flatclusterings = [ravel(clustering).astype(int) for clustering in clusterings]

could have been written as a simple map to ravel . astype(int) if the language was less complex (and more functional, to allow the partial application of astype(int))

allow "debug globals" that are only active when debugging


" Speaking as a Python person who recently had to dig through a Ruby project, I can see why people like Ruby and RoR? (lack of explicit return statements make your code look functional, lack of parens makes your code look minimal, it's nice to have "unless"), but it is not for me. " -- http://news.ycombinator.com/item?id=1749494


upto, each, for, until, like ruby

syntactic modifier for mutate-in-place and for unboxed

dict lookup should throw an exception upon KeyError?, like Python; if it just returns nil, like Ruby, then you can't tell if the value was nil, or if the key was missing. but there should be a syntactic modifier to convert KeyErrors? to nil returns that one can affix to any function.

syntactic modifiers are punctuation; function names are alphanumeric. by "syntactic modifier" i mean like a function decorator, but at the function call, not the function defn. i had another name for them above, i forgot what. anyway, "fold" is one of 'em

a synctatic modifier to infixify


clojure distinguishes between global and local symbols with a simple convention:

" A keyword that begins with two colons is resolved in the current namespace:

    In the user namespace, ::rect is read as :user/rect"

clojure supports ratios as a primitive data type. on could imagine generalizing this to support of abstract data types, even when the constituents map to implemented operations in terms of other, existing data types.

clojure forms include: symbols, strings, chars, java number types plus unbounded integers plus ratios, characters, nil, bools, keywords, lists, vectors, maps, sets


significant whitespace by default with optional braces, like haskell

tabs disallowed by default (flag to make them allowed)

if commas for lists, trailing commas allowed

should we do like this?:

" I think the creator of Merd got it (mostly) right -- our brains impose structure on code according to the whitespace in it, so the compiler should use that whitespace in the same ways that our brains do. A significant problem in programming languages is operator precedence -- quirks and differences between languages have left many of us not trusting the rules for operator precedence, or that the reader/writer understand them. Why not say that all operators have the same precedence but whitespace is significant? For example, in

   func1
       func2 a+1 * b-1
       func2 a-1 / b+1

we immediately interpret this, because of the whitespace, to mean

 ( func1
     ( func2 (a+1) * (b-1) )
     ( func2 (a-1) / (b+1) ) )"

recommended default is two spaces of indent. PEP8ish style guide at the beginning

use annotation to support an ! inplace meta operator/macro? then have everything in the std libraries be functional by default. ! would apply recursively. of course, for some ops the algorithm for inplace or not is very diff, i.e. filtering a list, if you copy it then just iterate thru and skip the bad items. use convention isSomething for things that return bool (save ? for something else). mb use #ip or something like that for inplace.

clojure actually has annotation, or "metadata"

integrate redis ops (mb just redis itself?!) into core libs


consider stuff like this to make it possible for the language to run fast:

http://blog.headius.com/2009/04/how-jruby-makes-ruby-fast.html


private and protected exist, but can be overridden with "override" or "publicize" or "peek" or somesuch


'$' prefix for variables (or '@'?) means "ask me no more questions, tell me no more lies", i.e. assume nothing about this variable (it may be mutated by foreign functions, etc), and its type is determined at runtime. variables without any prefix must statically typecheck


regex character parsing extensions include "shell backquote interpolation"-like thing to eval the results of a shell call, but also ways to have a block of code from other languages -- include drivers for popular jvm libraries like java, clojure, scala, etc


look at llvm, jvm, etc


primitives for programming languages:

syntax scanning, lexing, parsing, memory ("state"), transactions, and in general markers around bits of code with semantic meaning messages, parallelism and various parallel constructs, and ordering of execution proofs about the program ("typechecking assertions about parts of the program assertions about variables like Qi, these should be extendable loops recursion lists (in jasper, graphs) variables scope


from clojure:

. syntax for method invocation seems nice (and mb similar to what i already thought of?)

  1. _ is a macro that tells the reader to read the next thing, but then forget about it ->> (or was it --> or -> ?) is a macro for pipelining

(:user x) = (get :user x)

->> = "thrush"

[{giver :giver }]


here's a case where more syntax than Clojure provides would be beneficial:

(defn unassigned-transform [perspective] (let [unassigned (unassigned-person perspective)] (replace {unassigned (assoc unassigned :primary (:influence unassigned))} perspective)))

"replace" and "assoc" could be replaced by hash references in other languages, e.g.

perspective[unassigned] = perspective[unassigned]

isn't there a better way to do this in Clojure?


clojure reduce:

Usage: (reduce f coll) (reduce f val coll)

that's hard to read if you remember the short form but forget the long one; optional args should always go at the end

---

looking at clojure, i guess i should not make lines "backwards" (with the fn at the right side of the line) after all. you want to read the fn firt, so that you know what to expect in each argument position. it's like grammar/syntax (with ea. fn having its own grammar/syntax). opportunity for improvement: offer an array of std semantic "grammars" for fns. libs often do this, but don't explicitly codify it. since it's semantics, it can't (usefully) be formalized, but just do it in plain english.

convention: variable most likely to be unapplied goes at the end (like Haskell)


if you make macros go thru and AST first, make sure that there is a lib that lets ppl use that AST and that it preserves formatting/whitespace/comments etc on a roundtrip -- o/w ppl can't use it to make automated refactoring tools.

ruby_scribe attempts to intelligently format code (whitespace, etc) while deparsing from an AST without this sort of information

stuff like this should be built in: http://carboni.ca/projects/laser


if you have a bunch of procedures in the same module or "class" that call each other nad that pass around a common set of variables while calling each others (here you might use an instance variable if using OOP), have some syntactic sugar for passing those around without writing them -- but actually they are passed on the stack, not kept as common state (which would give problems with concurrent access from multiple threads)

mb these can use notation similar to instance vars:

default @@prefix "" default @@suffix ""

def myprintWithPrefix(str): print @@prefix print str

def myprintWithPrefixAndSuffix(str): myprintWithPrefix(str) print @@suffix

def myHelloWorld(name): myprintWithPrefixAndSuffix("Hello " + name)

myHelloWorld("Bayle", prefix = "output: ")

would compile to:

def myprintWithPrefix(str, prefix="", suffix=""):): print prefix print str

def myprintWithPrefixAndSuffix(str, prefix="", suffix=""):): myprintWithPrefix(str, prefix=prefix, suffix=suffix)

  print suffix

def myHelloWorld(name, prefix="", suffix=""): myprintWithPrefixAndSuffix("Hello " + name, prefix=prefix, suffix=suffix)

myHelloWorld("Bayle", prefix = "output: ")

so, these are not stored as state that persists across threads or between calls into the module, but when any outside function calls in and wants to override the defaults, this override is passed down within the module. Note: would also want to auto-pass in the special vars when constructing partially applied functions, so that if one of the functions in the module wants to call an outside function and pass some function in the module as a callback, the special variables are automatically passed.


want to support metaprogramming of things like the @@ syntax. In general, need to allow metaprogrammers an easy way to "flag" tokens with punctuation added as a prefix or suffix (e.g. in the above, we have a prefix flag of "@@").


mentioned this before, but.. do read http://users.rcn.com/david-moon/PLOT/index.html


if there is a nil (or, better, a ladder of escaped nils), then this should eval to false, everything else (including 0, empty string, etc) to true (but in a context where the result can be trinary instead of binary, nil evals to nil)


Ruby has Procs created with Proc or with lambda:

if a Proc is created with Proc, return is executed in the calling context, and number of arguments are not checked; if it is created with a "lambda", these aren't the case (according to http://eli.thegreenplace.net/2006/04/18/understanding-ruby-blocks-procs-and-methods). this distinction should be made at call-time, not at define time.

unlike Ruby, don't make up a special keyword ("yield") to call blocks to be passed without an argument name in the argument list of the receiving/calling function. it would be preferable make up a default argument name ("bloc") if you don't want them to have to be included in the argument list. also, b/c of the presence of anonymous procs, there is the ampersand for giving them a name (e.g. def myfunc(normal_arg, &deanonymized_proc)) and for passing named procs instead of using the special "block" passing syntactic sugar (see below) (e.g. a = [1,2]; plusone = lambda {

xx+1}; a.map(&plusone)), all of which would be simpler with a keyword argument name (& is also used to interpert a symbol name as a method and convert that method into a Proc, though: "words = %w(Jane, aara, multiko); upcase_words = words.map(&:upcase)", although this only works within the context of an argument list (!), regrettable lack of power).

in ruby, i think procs act as closures, whereas methods access the local state of the class.

in ruby, "blocks" are a syntactic construct {

var1, var2code} for creating Procs. they can't live on their own; "a = {xp x}" is a syntax error (you would use rather "a = Proc.new {xp x}" or "a = lambda {xp x}". there is syntactic sugar that uses a Block to pass a single Proc into a function: "a = [1,2]; a.map {xx+1}". This is useful and Jasper should have something like it, unless Jasper's syntax already makes this ez (which is likely) (although, as above, an extra keyword to call such as "yield" should not be used).

this pattern should be simplified:

      evals.each { |eval|
        giver_evaluation_sum[eval.giver_id] = 0 if !giver_evaluation_sum.has_key?(eval.giver_id)
        giver_evaluation_sum[eval.giver_id] += eval.amount if valid_receiver_fn.call(eval.receiver_id)
      }

list comprehension for fold? with default for a[i] += y in the case that a[i] doesn't yet exist (i.e. a += that has a default if the left arg is nil)?


some usecases for macros may be solved more simply if you just give a way for a subroutine to (a) return from the calling function (like Blocks in Ruby), (b) do other control-flowy things in the calling context (e.g. have an "else" if it's an IF, etc; although note that if else is syntactic this breaks compilation) and (c) set variables in the calling function (C-style languages with pointers allow this; you'd think so-called call-by-reference alnguages like Python does, but you can't actually set a scalar local variable in the calling context -- not everything is actually call-by-reference).

could it be GOOD to do like C and specify each variable as call-by-value (functional) vs. call-by-reference?


i mentioned this before but MATLAB style fn defs, where you can then just copy and paste the def line to use the fn, are useful.

---

i've mentioned this many times before, but hash slices are a must:

http://apidock.com/rails/Hash/slice

btw that page tells a good names for the *expand_array_inline operator; "splat". (in slice, there should be no splat, however)

btw their slice is "wrong"; if there's something that is in the slice spec but not in the hash, it should generate a hash leading to nil, not nothing, in the output


a = b or c should be parsed as a = (b or c) (unlike ruby, which does (a = b) or c)


need a shortcut for

lambda {

giver_id@influence_list_old[giver_id]}

(@influence_list_old.method :[])

--- need a shortcut for

{

xx.amount}

and

map({

xx.amount})

i think the former is

&:amount

and the latter is then map(&:amount)


in ruby you can "open classes", that is, alter stuff in them, and even the other libraries that call them will have the new, open behavior.

it would be good to also offer, as an option, "Shadow open classes" or module-scoped open classes that only affect the classes behavior when it was called from your namespace; e.g. you can override Hash.each, but when some other library constructs a hash and calls .each on it, it gets the old behavior. it isn't clear exactly how this should be done; if you modularly-open a class, and you construct a Hash, and pass it to a system library, which calls .each, does it get the old behavior or the new? that is, is the overriding scoped by the module of the caller or the module of the object creator? in the case in which the new behavior changes how state is maintained in the object, it must be consistent throughout the object's lifetime, so it must be the object creator. in the case of the ww


example of ruby easier to read (and slightly more concise) than clojure:

http://benmabey.com/2011/08/14/word-break-in-clojure-and-ruby-and-laziness-in-ruby.htmlhttp://benmabey.com/2011/08/14/word-break-in-clojure-and-ruby-and-laziness-in-ruby.html


ruby

module WordBreak?

  class << self
    def segmentize(string, dictionary)
      return string if dictionary.include?(string)
      string.size.times do |i|
        prefix = string[0..i]
        next unless dictionary.include?(prefix)
        remaining_segment = segmentize(string[(i+1)..-1], dictionary)
        return [prefix, remaining_segment].join(" ") if remaining_segment
      end
      nil
    end
  endend

clojure

(defn word-break [input dict] (if (contains? dict input) input (let [length (count input) candidates (map #(list (subs input 0 %) %) (range length)) prefixes (filter (fn [[c?]] (contains? dict c)) candidates)] (first (for [[prefix i] prefixes :let [suffix (-?> (subs input i length) (word-break dict))] :when suffix] (str prefix " " suffix))))))


quick analysis about undesirable things in ea. version:

as the blog post notes, the ruby version imperatively breaks out of the loop with next, whereas the clojure version is lazy, which is much better

cons on clojure: no syntactic sugar for slicing and ranges must go all the way down the tree and then all the way up to see what is returned; cannot just look for "return" keyword (in general, u cant in ruby either, e.g. if the last lines of the function body are a conditional, both conditions can be the return value) -- mb there is merit to requiring "return" keywords when not on the last line in ruby can just type "return" anywhere to break out of the whole function, even in the middle of a loop; this is a powerful yet easy to understand construct; one of the ways in which imperative programming makes thinking easier. clojure has to start with that "if" to accomplish the same thing. i guess the main benefit of not allowing return is making proofs about the code easier (in jasper, "return"s should be removed in one of the compiler pipeline stages, producing something like the clojure version, for the sake of macros that are reasoning about control flow)

why is clojure's candidates (map #(list (subs input 0 %) %) (range length)) prefixes (filter (fn [[c?]] (contains? dict c)) candidates)]

so much longer and more complicated than ruby's string.size.times do

i
        prefix = string[0..i]
        next unless dictionary.include?(prefix)

? that part seems to the key difference (note that to be really equivalent, we'd include the "(let [length (count input)" on the clojure side too)

  i'm not sure that it really is; the complexity of the anonymous fn in clojure is offset by the complexity of the .times loop in ruby
  in clojure, stuff inside the scope of the let is literally inside its parens. this adds needless cognitive complexity; when would you ever need do have other things in the same function but outside the scope of a let? the lisp way better matches the formal structure of proofs about the computation, but in this case the part of the proof it captures is trival and the degree of freedom it enables is unused due to convention. imperative languages let your reasoning about time take the place of the timeless mathematical-style reasoning; it's better just to have everything after an assignment, but in the same function, be in the scope of that assignment.

so far, we've discovered a few ways to improve clojure; syntactic sugar for hash assignment and hash lookup (not covered here); syntactic sugar for slicing and ranges; mandatory "returns" when not at the end; optional "returns" to break out of a fn, without using conditionals and introducing an extra scope; implicit scoping of lets. so we'd have something like:

(defn word-break [input dict] (if (contains? dict input) return input) (let [ candidates (map #(list input[0..%] %) input.size) prefixes (filter (fn [[c?]] (contains? dict c)) candidates) ] (first (for [[prefix i] prefixes :let [suffix (-?> input[i..length] (word-break dict))] :when suffix] (str prefix " " suffix)))))

  what if we just used = instead of let

(defn word-break [input dict] (if (contains? dict input) return input) = candidates (map #(list input[0..%] %) input.size) = prefixes (filter (fn [[c?]] (contains? dict c)) candidates) (first (for [[prefix i] prefixes :let [suffix (-?> input[i..length] (word-break dict))] :when suffix] (str prefix " " suffix))))

in case the parens are biasing:

defn word-break [input dict] if (contains? dict input) return input = candidates map #(list input[0..%] %) input.size = prefixes filter (fn [[c?]] (contains? dict c)) candidates first (for [[prefix i] prefixes :let [suffix (-?> input[i..length] (word-break dict))] :when suffix] str prefix " " suffix))

now compare to ruby:

  class << self
    def segmentize(string, dictionary)
      return string if dictionary.include?(string)
      string.size.times do |i|
        prefix = string[0..i]
        next unless dictionary.include?(prefix)
        remaining_segment = segmentize(string[(i+1)..-1], dictionary)
        return [prefix, remaining_segment].join(" ") if remaining_segment
      end
      nil
    end
  endend

hmmm... not quite there yet.. the clojure needs some foruther analysis/reduction.

i can't say that i understand the for [[prefix i] prefixes :let [suffix (-?> input[i..length] (word-break dict))] :when suffix]

well enuf yet tho..

i think passing the i in the ruby loop variable is simpler than passing it as a tuple in the lazy list, and then having a for construct later anyway. not sure what to do about that.

"

sesqu 208 days ago

link

When you look at lisp code, all you have to go by are the names of functions. The code could do anything, and you won't find out what until you dig. By contrast, other languages have hints like types and standard, well-understood libraries and restrictions on what might happen.

This suggests lisp code is less approachable for second authors, precisely because of its expressiveness. "

http://www.teamten.com/lawrence/writings/the_language_squint_test.html

---

should be no difference between attribute lookup on an object ref and lookup in a hash/dictionary

(note: the library Mash from https://github.com/intridea/hashie appears to do this in Ruby!)

--- ruby's 'include' is ok but should also have a raw #include that e.g. doesn't evaluate __FILE__ first, etc.

---

https://github.com/ffi/ffi/wiki

Ruby-FFI is a ruby extension for programmatically loading dynamiclibraries, binding functions within them, and calling those functionsfrom Ruby code. Moreover, a Ruby-FFI extension works without changeson Ruby and JRuby. Discover why should you write your next extensionusing Ruby-FFI here[2].

--- a-b should be just a token; only a - b is subtraction (or a--b)

---

constructs from R

> x[x>3] # list of elements in x greater than 3 [1] 10 5

> names(x)<-colors # assign the names using the character vector colors > names(x) [1] "green" "blue" "orange" "yellow" "red" > x green blue orange yellow red 1 3 2 10 5 > x["green"] # component reference by its name green 1 > names(x)<-NULL # names can be removed by assigning NULL > x [1] 1 3 2 10 5

> seq(10) [1] 1 2 3 4 5 6 7 8 9 10 > seq(0,1,length=10) [1] 0.0000000 0.1111111 0.2222222 0.3333333 0.4444444 0.5555556 0.6666667 [8] 0.7777778 0.8888889 1.0000000 > seq(0,1,by=0.1) [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0

> m2[2,3] #element of m2 at the second row, third column [1] 2 > m2[2,] #second row [1] 5 -1 2 > m2[,3] #third column [1] 2 2 9

> m2[-1,] #submatrix of m2 without the first row [,1] [,2] [,3] [1,] 5 -1 2 [2,] 2 3 9 > m2[,-1] #ditto, sans the first column [,1] [,2] [1,] 3 2 [2,] -1 2 [3,] 3 9 > m2[-1,-1] #submatrix of m2 with the first row and column removed [,1] [,2] [1,] -1 2 [2,] 3 9

y.fun<-function (x) {y<-(log(x))^2-x*exp(-x^3) }

$word might be like .'word' or .:word or or ['word']

Cross tabulation is very easy, too: > table(Car$Make, Car$Type)

             Compact Large Medium Small Sporty Van
  Acura      0       0     1      0     0      0
  Buick      0       1     0      0     0      0
  Chevrolet  1       0     0      0     0      0
  Chrysler   0       0     1      0     0      0
  Dodge      0       0     0      0     0      1
  Eagle      0       0     0      1     0      0
  Ford       0       0     0      1     0      0
  Honda      0       0     0      0     1      0
  Mitsbusihi 1       0     0      0     0      0
  Volkswagen 0       0     0      1     0      0 

What if you want to arrange the data set by vehicle weight? order() gets the job done. > i<-order(Car$Weight);i [1] 1 5 3 4 2 7 10 6 9 8 > Car[i,] Make Model Cylinder Weight Mileage Type 1 Honda Civic V4 2170 33 Sporty 5 Volkswagen Jetta V4 2330 26 Small 3 Ford Escort V4 2345 33 Small 4 Eagle Summit V4 2560 33 Small 2 Chevrolet Beretta V4 2655 26 Compact 7 Mitsbusihi Galant V4 2745 25 Compact 10 Acura Legend V6 3265 20 Medium 6 Buick Le Sabre V6 3325 23 Large 9 Chrysler New Yorker V6 3450 22 Medium 8 Dodge Grand Caravan V6 3735 18 Van

If you want to modify the data object, use edit() function and assign it to an object. For example, the following command opens notepad for editing. After editing is done, choose File

> y<-edit(y)
Save and Exit from Notepad.

If you prefer entering the data.frame in a spreadsheet style data editor, the following command invokes the built-in editor with an empty spreadsheet. > data1<-edit(data.frame())

> attach(fuel.frame) attach() allows to reference variables in fuel.frame without the cumbersome fuel.frame$ prefix.

what does this mean? lm(eruptions~waiting)

how does this work?

abline(lm(Mileage~Weight))

" R's "formula" notation

One nice thing about using R is that it shares a common kind of notation across a lot of different functions. Learning this "formula" notation takes a little time, but it's easy to use once you've got a grip on it. The basic form is: Y ~ X

... where "Y" is your dependent variable (the thing you're trying to predict) and X is the model of effects you're dealing with, which may potentially include lots of different things. Here are some key points to know about using this notation:

    Only a single measure (i.e., a single vector) can be used as the dependent measure.
    The basic way to have multiple predictor terms (the right side of the formula) is to use "+". For example:
    Y ~ factor1 + factor2
    To specify an interaction term, use a colon (":"). For example, if you want to use a model of the simple effects and interaction of two factors, you could use:
    Y ~ factor1 + factor2 + factor1:factor2
    A shorter way to do the above is to use "*", which is shorthand for all the simple effects and all the interactions. That is, the following is exactly equivalent to the previous formula:
    Y ~ factor1*factor2
    You can use parentheses to help specify groupings. For example, the following are equivalent:
    Y ~ (factor1 + factor2)*factor3*factor4
    Y ~ factor1*factor3*factor4 + factor2*factor3*factor4
    The vectors on the right side are treated as factors. Much of the time, if they are not already factors, R will coerce them into being factors temporarily. But you may want to make sure they are factors to begin with. See here for how to do this." -- http://internal.psychology.illinois.edu/~srjacksn/Rtests.html#formula

quick way of doing debug statments that are the next line with vars subbed e.g.:

        self.log.log(1, 'reqMktData(%d,%d,'',%s)" % (`tickerId`, `contract`, `snapshot`))
        self._ib.reqMktData(tickerId,contract,'',snapshot) 

note: clojure doesn't have a nice [] syntax for array/dict lookup; this is essential


the syntax for returning value should be just as flexible as the syntax for passing in function arguments; it should have optional arguments, keyword arguments, etc


must make it trivial to always return a future instead of blocking, sleeping, waiting, etc


i've said this before but want to emphasize how tedious it is to do:

        super(BrokerIb, self).__init__(log = log, accountName=accountName, currency=currency, shouldConnect=shouldConnect, subscribeUponOrderPlacement=subscribeUponOrderPlacement, subscribeUponGetCurrentPrice=subscribeUponGetCurrentPrice, clearCache=clearCache, clientId=clientId)

even if the wrapped function takes a subset of arguments of the wrapper, e.g.:

class Broker(object): def __init__(self, log = logging, accountName=None, currency='USD', shouldConnect=True, subscribeUponOrderPlacement=True, subscribeUponGetCurrentPrice=True, clearCache=True, kwds):

class BrokerIb?(Plugin, Broker): implements(IBroker)

    def __init__(self, clientId=0, log = logging, accountName=None, currency='USD', timeout = 30, sleepDuration = 0.1, orderIdRequestBatchSize=1, shouldConnect=True, subscribeUponOrderPlacement=True, subscribeUponGetCurrentPrice=True, waitBetweenHistoricalDataRequests = 10, subscribeLatencyTime=1, clearCache=True):
        super(BrokerIb, self).__init__(log = log, accountName=accountName, currency=currency, shouldConnect=shouldConnect, subscribeUponOrderPlacement=subscribeUponOrderPlacement, subscribeUponGetCurrentPrice=subscribeUponGetCurrentPrice, clearCache=clearCache, clientId=clientId)

need to have ez syntax for composition/wrappers!

(note: in python, if you dont need the args yourself or are willing to get them manually, you can just do *args, kwds)


when iterating over a dict (node), either you want to iterate over keys, or over values, or over tuples of (k,v)


zeromq for erlang-style concurrency


syntatic support for extension points (component architecture)

interpreter support for overlays (aspect-oriented programming?)


graph structure should generalize dataframes, lists, dicts


better than python: tracebacks should (optionally?) print out values of all vars


python `backquotes_repr` is very convenient, i dont like that they got rid of it in python 3


needs to be ez to write wrappers that eat some kw args, e.g. the following in Python which adds an optional comment to results:

def _do_and_mb_comment(fn, *args, kw): if 'comment' in kw: commment = kw['comment'] del kw['comment'] else: comment = results = fn(*args, kw) results['comment'] = comment return results


Footnotes:

1.

2.

 mapfn(x) | list (if cond)

3. x.2

ex

4. x.price*2 in table.row if x.color == "red"