I commend you on making a beautiful little language. I have long suspected that what you call "concatenative" style is where PLs should be heading, and you've gone and done it!
Thoughts:
1: Did you really mix {} enclosed scope and whitespace sensitive scope following : ?
2: In a concatenative language, every enclosed expression is also a function:
3: In a concatenative language, type expressions (like (-> +IO +Exit) above) are just another function which the compiler can decide whether to resolve at compile-time or run-time
You propose this syntax for matching:
define read_x_y (Char, Char -> Optional<Move>):
match (dup2 try_read_x_y)
case some: \drop2 dip some
case none: swap try_read_x_y
But this dilutes your syntax IMO, it could look like this:
Here we are applying a strict rule that parens () denote type constraints, and braces {} denote scopes/control flow. When the compiler encounters a type constraint, it decides whether it can be resolved at compile time (this is valid or invalid code), or at run time (some kind of branch is taking place).
If statements are also just run-time dependent-type constraints, and similarly, loops are constraints that get reevaluated at the end of the activated scope:
define parse_move (List<Char> -> Optional<Move>):
-> chars;
do (with (+Fail)):
if (chars length = 2):
(chars 0 get from_some)
(chars 1 get from_some)
read_x_y
elif (chars length = 1 && { chars 0 get from_some = 'q' }):
forfeit some
else:
none
(constraint1) {scope1} (constraint2) {scope2} {scope3} behaves like
if (constraint 1) {scope1} else if (constraint2) {scope2} else {scope3}
I don't know if you like this... but I do :D
Of course, if you follow this approach, you will run into problems scoping other expression types without the use of () my suggestion would be to exchange () and {} such that parens denote scope, and braces denote constraints.
I commend you on making a beautiful little language. I have long suspected that what you call "concatenative" style is where PLs should be heading, and you've gone and done it!
Thoughts:
1: Did you really mix
{}
enclosed scope and whitespace sensitive scope following:
?2: In a concatenative language, every enclosed expression is also a function:
{play_round maybe_play_again}
has the type(-> bool)
, and this function could be written:3: In a concatenative language, type expressions (like
(-> +IO +Exit)
above) are just another function which the compiler can decide whether to resolve at compile-time or run-timeYou propose this syntax for matching:
But this dilutes your syntax IMO, it could look like this:
Here we are applying a strict rule that parens
()
denote type constraints, and braces{}
denote scopes/control flow. When the compiler encounters a type constraint, it decides whether it can be resolved at compile time (this is valid or invalid code), or at run time (some kind of branch is taking place).If statements are also just run-time dependent-type constraints, and similarly, loops are constraints that get reevaluated at the end of the activated scope:
could look like this:
The implication here is that
(constraint1) {scope1} (constraint2) {scope2} {scope3}
behaves likeif (constraint 1) {scope1} else if (constraint2) {scope2} else {scope3}
I don't know if you like this... but I do :D
Of course, if you follow this approach, you will run into problems scoping other expression types without the use of
()
my suggestion would be to exchange()
and{}
such that parens denote scope, and braces denote constraints.