JMP's scripting language, JSL, is built out of function calls. Pretty much everything you can write in JSL is a function call. Some things don't look like function calls:
A = A + 3;
It's pretty obvious the right-hand-side of the assignment statement is an expression. It's less obvious the assignment statement itself is an expression.
E = expr ( A = A + 3 );
expr is a wrapper that you can use around an expression to prevent the expression from evaluating. E is set to the expression, not the expression's evaluated result. To take a peek at E, use the head function. Head will return the name of the function at the root of the expression:
show( head(E) );
Head(E) = Assign();
Now you see there is a function for making assignments:
Assign( testing, 3+4 );
7
show(testing)
testing = 7;
Expressions in JSL are actually trees. Here's a picture of the a=a+3 tree, root at top, leaves at bottom:
Similar to the Head function, we can use the Arg function to access the children of the Assign function:
show( arg(E,1) );
Arg(E, 1) = A; the left-hand side
show( arg(E,2) );
Arg(E, 2) = A + 3; the right-hand side
and digging deeper,
show(head(arg(E,2)))
Head(Arg(E, 2)) = Add(); the head of the right-hand side
show(arg(arg(E,2),1))
Arg(Arg(E, 2), 1) = A; the left side of the plus
show(arg(arg(E,2),2))
Arg(Arg(E, 2), 2) = 3; the right side of the plus
Notice how the parenthesis nesting describes the tree. This tree only has binary splits. There is a function, narg, that returns the number of children. It returns 0 for leaf nodes.
narg(E)
2 the assign function has two arguments, the left-hand side and the right-hand side
JMP's for statement is a function call, taking four arguments. Notice the commas separating the arguments, just like any other function.
halfCats = 1;
for( iCat = 1, iCat <= 10, iCat++,
halfCats = halfCats / 2;
write( iCat, " ", halfCats , "\!n" )
);
1 0.5
2 0.25
3 0.125
4 0.0625
5 0.03125
6 0.015625
7 0.0078125
8 0.00390625
9 0.001953125
10 0.0009765625
It takes three commas to separate four arguments. In this for statement, the fourth argument is two statements, separated by a semicolon. Peek at the fourth argument to see if it is actually a function too:
Head(
Arg(
Expr(
For( iCat = 1, iCat <= 10, iCat++,
halfCats = halfCats / 2;
Write( iCat, " ", halfCats, "\!n" );
)
),
4 /* the fourth arg */
)
);
Glue()
Glue is the name of the function that holds a sequence of statements together. Glue's first argument is the first statement, etc.
Arg(
Arg(
Expr(
For( iCat = 1, iCat <= 10, iCat++,
halfCats = halfCats / 2;
Write( iCat, " ", halfCats, "\!n" );
)
),
4 /* the fourth arg is two statements, glued together */
),
1 /* the first arg is the first of the two glued statements */
);
halfCats = halfCats / 2
A JSL list is the same sort of expression:
list={33,44,55};
show(head(list));
show(narg(list));
show(arg(list,3));
Head(list) = {}; list displays curly brackets for the head, rather than a name like Assign
N Arg(list) = 3;
Arg(list, 3) = 55;
If you just want the contents of the list, you should use normal subscripting:
show(list[3]);
list[3] = 55;
But sometimes you want to do something like turning a list into arguments to a function.
In the Elephant post you'll find an example of turning a list into a pattern (line 5). I'm having a hard time coming up with another example as cool as that one, but suppose you wanted to check if the list was in alphabetical order. JMP's < operator can do that in a single function call:
LT = expr("a"<"b"<"c"<"d");
show(head(LT));
show(narg(LT));
Head(LT) = Less(); the less-than operator displays a function name, Less
N Arg(LT) = 4;
The Less function can take a lot of arguments, but you don't have to type them. Below, NameExpr is retrieving the expresion stored in words, after the SubstituteInto modified the { list } to be Less(). JMP then displays the Less function using < to make it more readable.
words =
{"Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", "Hotel", "India",
"Juliet", "Kilo", "Lima", "Mike", "November", "Oscar", "Papa", "Quebec", "Romeo",
"Sierra", "Tango", "Uniform", "Victor", "Whiskey", "Xray", "Yankee", "Zulu"};
Substitute Into( words, Expr( {} ), Expr( Less() ) );
nameExpr(words);
"Alpha" < "Bravo" < "Charlie" < "Delta" < "Echo" < "Foxtrot" < "Golf" < "Hotel" <
"India" < "Juliet" < "Kilo" < "Lima" < "Mike" < "November" < "Oscar" < "Papa" <
"Quebec" < "Romeo" < "Sierra" < "Tango" < "Uniform" < "Victor" < "Whiskey" < "Xray" < "Yankee" < "Zulu"
eval(words)
1 eval(words) returns 1, indicating the result of Less was true.
Another example.
Update 28Feb2017 - repair formatting for new community