BONES
Bones is a minimalist functional language syntax - primarily influenced by Smalltalk, Python, q/kdb and Rebecca Wirfs-Brook's Responsibility Driven Design.
The syntax defines expressions, modules, functions,
lists ((...)
for immediate and [...]
for deferred evaluation), basic literals
(int, float, time, string, symbol, table, etc), names and
name assignment, scopes (including access), struct (r/o) and repository (r/w)
access, line and block comments, sections (for embedding) and
types and type tagging. The only statements are python style imports.
The syntax is read left to right and is \n
and ;
separated with \
for line
continuation.
Functions may be called using a piping syntax where " " (<space>) is used
instead of the more familiar|>
or >>
etc.
Names may refer to structs or functions.
Names that refer to functions are called verbs and come in nullary, unary and binary flavours depending on how they interact with the piping syntax. Unary verbs - the most common - can take one piped argument, binaries two (most operators are binary) and nullaries can not be piped.
Partial functions may be created by passing less arguments than required for execution. Application of lists to verbs take precedence to piping - so piped argument are added to the end of the argument list. This style is slightly more uniform and flexible than the other common convertion of using piping to substitute the first argument. For example:
fred: {[a,b,c,d]...} <:unary:> // define unary verb fred with arguments a, b, c & d
partialFred: fred("A", "B") // partialFred is now fred["A", "B", c, d]
partialFred: partialFred(,"D") // partialFred is now fred["A", "B", c, "D"]
result: "C" partialFred // get the result
Implementations of verbs may be provided by external libraries - infact without at least some verbs being implemented externally bones can do very little other than return literals. AST fragments may be passed to and evaluated by external functions. This allows a library to implement flow control by selectively evaluating (or re-evaluating) those fragments.
Example, to implement the if
verb,
answer: b > 5 if("greater than five", "not greater than five")
a Python library may export a function implementing if
as a unary verb:
@export('if<:unary:>')
def myIfImp(trueAst, falseAst, conditionAst):
# usual calling convention is:
# <condition expr> if(<true expr>, <false expr>)
if conditionAst.value:
return trueAst.value
else:
return falseAst.value
Example, to implement ifTrue:ifFalse
(i.e. Smalltalk keyword style which is
implicitly unary),
b > 5 ifTrue: "greater than five" ifFalse: "not greater than five"
or
b > 5 \
ifTrue: "greater than five" \
ifFalse: "not greater than five"
in bones:
ifTrue:ifFalse::{[cond, trueExpr, falseExpr]
cond value if[trueExpr, falseExpr]
}
or, in Python::
@bones.export('ifTrue:ifFalse:')
def _if(conditionAst, trueAst, falseAst):
if conditionAst.value:
return trueAst.value
else:
return falseAst.value
Fold, here,
(1,2,3) fold(0) {(prior, each) prior + each}
could be implemented:
@bones.export('fold<:binary:>')
def foldImpl(seed, iter, fn):
answer = seee
for e in iter:
answer = fn(answer, e)
retun answer
Sum then can be defined in bones as,
sum: fold(0,,{(prior, each) prior + each}) <:unary:>
(1,2,3) sum
Some basic pragmatics - type system, variable contexts and closures and symbol handling, etc - are provided, as well as an example standard library written in bones and Python.