What if we insist that both branches of a branch have compatible types?
For one thing `[+] [* +] branch` leads to a circular term which, when
printed, goes into a loop: "int,int,int,...". Hmm...
I know there are better ways to do this, but I don't know what they are
yet. Maybe a "do" loop? Anyway, this works, although it doesn't catch
errors yet.
Like a total newbie I put the call to the interpreter in the view
function instead of the update function! I thought it was weird having
to specify the HTML twice, but I figured I was just doing it wrong. I
was, but not in the way I suspected.
In any event, I like how this make it clear that errors can't affect the
dictionary.
I forget why I was doing "not not" so I made it a little more clear. In
practice this is regressive: The built-in "isnt_bool" function should
be in the dictionary? Or prohibit type checking and let the bugs flow?
Rely on inference to prevent bugs that would pass the non-checking
versions of the functions? Hmm...
This is mostly for fun, but I bet it comes in handy, eh?
At the very least, it's a nice catalog of the possible errors that the
basic Joy system might encounter.
Just sqr for now, but it shows that it works.
I would like to return Results from add_def but it makes using foldl
slightly tricky, not a lot, just slightly, and my brainpower is low at
the mo'.
I don't like passing the stack through isnt_int but that let's you chain
with andThen.
There's probably a clever or idiomatic way to not do that and couple the
stack to the result without passing it through the type checker function
but I don't know what it is right now, and this works.
It's a simple task, but I'm not up on my CLI tools, so I went with
Python instead of sh. The split command doesn't have '-p' switch on
Ubuntu. (I'm using Ubuntu on this laptop because it can correctly
configure the WiFi and the laptop has no ethernet port.)
I have it broken up into three stages: a parser that reads a string from
stdin and emits (Prolog) AST to stdout; an interpreter of sorts that
reads AST from stdin, evaluates it, and then emits the AST of the stack
on stdout; and a printer that reads AST on stdin and prints Joy-ish code
to stdout.
I say Joy-ish because currently math is not evaluated and results of
math appear as expressions, not values.
This is because GNU Prolog doesn't have unbounded integers (it's numbers
are machine integers) so literals that are larger than the machine word
are converted into atoms! To keep things simple, I made all ints into
atoms, but then you can't evaluate them: '1'+'2' is not '3' (it might be
'12' though.)
So I print them out at expressions:
$ echo "1 2 3 4 [+ sub /] i" | ./joy_to_ast | ./thun | ./printer
(1 div (2-(4+3)))
You could almost feed that to, say, Python to evaluate, eh? Or dc with
proper formatting? (man dc; "Desk Calculator".)
Anyway, it's a start. The Prolog interpreter is more for things like
type checking and inference, optimizing, compiling, etc. Symbolic stuff
that's a PITA to express in other languages. (The old type inference
code in Python was pages long, in Prolog it's just the thun/3 & thun/4
predicates themselves. At least so far. There are things we will want
to do eventually that might be a PITA to express in Prolog, eh?
On a lark I implemented it in recursive style, but I'm not going to keep
it that way. I have to implement next_term() first and then I'll
uncomment i_joy_combinator().