Hi,
I'm working on a language that would be simple to learn. I teach IT in a training center (mostly MS products), and I noticed that what people find hard is:
- nested parentheses hell (3 is already hell, we don't do LISP ;) )
- the fact that a function name precedes parentheses
- function parameters have precise syntax, where order matters
For example, I often see things like:
=if(A1="ok";and;B1<0;C1;D1)
You can feel what was intended.
So, I put strong constraints on the language expressiveness, just to see where it leads.
It looks a bit like INI files.
You start function definition with the name of the function between square brackets.
You have only one command per line
Commands only take one argument, which is always a string
Syntax is "function: argument"
You can call functions inside parentheses, with the same syntax
You CANNOT nest parentheses
You can access variable by their name between angle brackets
You CANNOT nest variable names
Inside a function's body, argument is accessed through empty variable name <>
The return value of last command is always stored in variable <this>
That's it
Here is a taste.
[repeat twice]
render: <> <>
[main]
about: cars
print: Now "this" means <this>
about: language
store this in: some variable
print: what a (repeat twice: really) awful programming <some variable>
==> Now "this" means cars
==> What a really really awful programming language
[pattern match]
parse this as: * isn't *
wildcard in: first
wildcard in: second
render: 1st is <first> and 2nd is <second>
[main]
print: (pattern match: parsing isn't that hard)
==> 1st is parsing and 2nd is that hard
[about]
new meaning of "this"
[render]
choose result value
[store this in]
store value of "this" in named variable
[print]
write text on screen
[parse this as]
do pattern matching on sentence
[wildcard in]
store capture in named variable
This language is intended to be used to code agent behavior in a multi-agent middleware, probably hosted in CouchDB, inspired from a previous work (http://noisett.lang.free.fr/). Feel free to borrow bits and pieces!
You said, "Commands only take one argument, which is always a string"
My question is, how would recursion be supported with only one argument?
My informal suggestion:
[recurse thrice]
split: thrice
random: thrice
render: <random>
[main]
about: recursion
print: pseudocode
about: AI
store <Zero> in: friend
print: response (recurse thrice: hello|greetings|howdy) to you too <friend>
Shader programming for ai? Sure thing, next to custom 1-0 hardware its the best you have for a basic consumer system. If you wanted to handle strings, you have to treat them like binary pictures, youll find any data type will make an image of some kind and it makes no difference.
Cool. It's definitely worth investigating! I like pattern matching, and I also like cellular automata. Hey, we should do a pattern matching-based cellular automata :D
You said, "Commands only take one argument, which is always a string"
My question is, how would recursion be supported with only one argument?
Do we need more than one argument to recurse? (and no one told me?)
// 1. if n is 0, return 1
// 2. otherwise, return [ n × factorial(n-1) ]
[factorial]
if: <> eq 0 // test if argument is zero
render: 1 // if yes, return 1
end: if // end of if block
about: <> // put argument in <this>
decrement: 1 // put <this>-1 in <this>
store this in: arg // put <this> in <arg>
about: <> // put argument in <this>
multiply by: (factorial: arg) // put <this> times factorial of <arg> in <this>
render: <this> // return <this>
[main]
print: Please choose a positive number:
input: <num>
print: Factorial of <num> is (factorial: <num>)
It seems to work. What do you think? Actually, I'm cheating: <this> (which is the result of previous command) often acts as implicit second argument. Example: "store this in". See?
EDIT: Since it's based on string substitution, we can still so a few funny things. String substitution happens before command is executed, so:
[Put function in variable]
about: print
store this in: foo
<foo>: hey!
[use function result as variable name]
print: now I'll <(choose what to do: next)>
[use function result as function]
(choose what to do: next): with something
Maybe I should be more strict about these.
And I'd like to get rid of code blocks. I don't like this "if/end if" thing. Shall we dare evil gotozzz?
Please help me port my bits and pieces
in the comments (to the right of my PHP).
Note: I may have implemented this Tail-recursive
optimization a little different for A.I. research.
The comments are pseudo code surrounded
by: /* comments_go_here */ I took an educated
guess on the else statement as well as on other
syntax in your language.
By the way, what's your language called?
Thanks!
<?php
/* Tail-recursive optimization */
function tro($arg, $this) { /* [tro] */
if($arg <= 1){ /* if: <> le 1 */
echo "$arg "; /* print: <arg> */
return $this; /* render: <this> */
}else{ /* else: */
echo "$arg $this\n"; /* print: <arg> <this> */
return tro($arg-1, $this * $arg);
/* decrement: 1 */
/* store this in: arg */
/* about: <> */
/* multiply by: (tro: arg) */
/* render: <this> */
}
}
echo tro(8,1)."\n";
?>
PHP OUTPUT:
8 1
7 8
6 56
5 336
4 1680
3 6720
2 20160
1 40320
Hi,
Well, since there's only one argument, you cannot access what was <this> when you called the function from inside the function. You have to insert $this in $arg.
So I guess that a line by line translation would be:
function tro($arg, $this) { /* [tro] */
/* parse this as: *,* */
/* capture in: $a */
/* capture in: $t */
if($arg <= 1){ /* if: <$a> le 1 */
echo "$arg "; /* print part: <$a>\s */
return $this; /* render: <$t> */
}else{ /* else: */
echo "$arg $this\n"; /* print line: <$a> <$t> */
/* about: <$a> */
/* decrement: 1 */
/* store this in: $deca */
/* about: <$t> */
/* multiply by: <$a> */
/* store this in: $mult */
return tro($arg-1, $this * $arg); /* render (tro: $deca,$mult) */
} /* end: if */
}
/* [main] */
echo tro(8,1)."\n"; /* print line: (tro: 8,1) */
But it all depends on your base instruction set. For example, for a multi-agent middleware, here is a work-in-progress instruction set:
[about] // Put argument in <this>
[anyway] // Stop skipping commands, and put argument in <this>
[render] // Choose return value
[when message matches] // Start skipping commands if message doesn't match argument
[when message doesn't match] // Start skipping commands if message matches argument
[send] // Send argument to every followers
[send to myself] // Send argument to myself
[send to my tables] // Send argument to agents owning links where I'm involved
[forget this in] // Delete everything that matches a pattern in a variable
[push this in] // Push <this> in a variable
[pop from] // Pop <this> from a variable
[unshift this in] // Push <this> at the other end in a variable
[shift from] // Pop <this> from the other end in a variable
[rotate] // Rotate list stored in a variable
[when something in this matches] // Start skipping commands if nothing in a variable matches argument
[when nothing in this matches] // Start skipping commands if something in a variable matches argument
[pick a random element from] // Pick a random element from a variable
[put capture in] // Put what next wildcard has captured in a variable
[list agents having this once in] // List of agents having this pattern in given key
[list agents having only this in] // List of agents having this pattern in given key
[list used variables] // List of every variable
[if all identical] // Parse argument if everything in this is the same
[if one different] // Parse argument if something in this is not the same
[for each one] // Put next element in this, parse argument, do it again
<message> // The current message
<message sender> // Id of agent who sent current message
<me> // Id of me
[follow input of]
[follow output of]
[follow upput of]
[follow action of]
In that case, instead of raw recursion, an agent would probably send a message to itself about the next iteration, which is a bit like tail recursion. I'm working on a Nodejs implementation currently.
About the name, I don't know yet, so if you guys have ideas, they're welcome!
:)
Then we should name it "fantASM". Big hit! :o ;D
EDIT: So far, I have
log to console: (execute raw javascript: 5+5)
working!
Hi all,
This language is evolving a bit. I wasn't happy with having colons inside parentheses, so now functions act as chatbot triggers. They're defined between curlies.
{first name of *}
command: argument
command: argument
render: something
[regular command]
command: argument
insert: (first name of Joe Black)
command: argument
Now, indentation matters. Also, the target has changed, it is now a language that compiles to a single html file, containing html5+css3+js. I still dont' have a name. PL/DS could mean "dead simple" :)
EDIT: Would "Litewave" be a good name?
Indentation is maybe too much for an "easy" language. So, maybe jumping a line to mark the end of a code block would suffice. Like:
[my command]
print: Here is a list of cities I like:
for each item from: <list of cities>
print: I like <item>
print: That's it!
Nesting foreach loops wouldn't be allowed in that case.
Here is a draft command set:
[list vars like] produces a list of variables with name matching given pattern
[with] appends its argument to <this>
[without] removes from <this> everything matching its argument
[only] keeps in <this> everything matching its argument
[keep before] keeps in <this> everything before first match
[keep after] keeps in <this> everything after last match
[about] puts its argument in <this>
[this is] puts what is in <this> in the variable with the given name
[forget variable] deletes variable with given name
[raw] produces directly its argument (without string interpolation)
<this>
[here is] defines a label you can jump to
[jump to] jumps to a label
[if] executes code only if its argument is in <truth>
[unless] executes code only if its argument isn't in <truth>
[while] keeps looping code while its argument is in <truth>
[until] keeps looping code until its argument is in <truth>
[for each item from] executes code once for each value of its argument
[if this is] executes code only if <this> is the same as its argument
<item>
[consider] asserts strings in <truth>
[sufficient] asserts a "sufficient" rule
[necessary] asserts a "necessary" rule
[put aside] removes from <truth> strings matching its argument
[keep and formulate] produces a list of strings based on possibilities
[formulate] produces possibilities and delete logic variables
[forget logic] deletes logic variables
[truth in] saves the content of <truth> in variable with given name
[truth from] loads the content of <truth> from variable with given name
<truth>
[list nodes like] lists html nodes using "document.querySelectorAll()"
[select node] selects current node using "document.getElementById()"
[remove node] deletes node with given id
[clear node] deletes the content of node with given id
[set as attribute] puts <this> in given attribute of current node
[get attribute] puts given attribute of current node in <this>
[before node put] inserts node of given type before current node and produces its id
[after node put] inserts node of given type after current node and produces its id
[inside node put] inserts node of given type inside current node and produces its id
[write] appends given text in current node
[listen] puts a listener on current node with following code block
[ignore] deletes a listener from current node
<node>
<ui>
Sorry, I wasn't able to respond sooner. Thanks a lot for your input!
So yes, you got it. What I call "commands" here are named "subs" in basic, "procedure" in pascal, "function" in C. My previous post was a list of built-in commands.
To define a new command, you put its name between square brackets. Programs always start by executing the "main" command. So a basic hello world would be:
[main]
print: Hello world!
It's a little bit early to write a tutorial, but when I'm done I'll make one, and if this tutorial is not clear, maybe you can help me make it better :)