JohnEarnest / ok

An open-source interpreter for the K5 programming language.
MIT License
587 stars 72 forks source link

Crash #12

Closed refi64 closed 9 years ago

refi64 commented 9 years ago

This:

(" ",)/"abc"

probably doesn't work but makes oK freeze (which probably is not desired behavior!).

JohnEarnest commented 9 years ago

Well, it's an infinite loop- " ", is essentially ,[" ";], which is a monadic function. When you use "over" with a monadic function it's the "fixed point" form, and since every application of the monad creates a longer string it won't stop.

Infinite loops are a problem in oK's current incarnation- a known issue with only complex solutions. There was some discussion about this in issue #6. In the short term, a good way to avoid losing your work to lockups is to use the \e "editor pane" in the browser frontend. The contents of the text editor is saved in local storage before executing any code fragments, so refreshing the browser will stop the program and allow you to recover your work.

JohnEarnest commented 9 years ago

Are you satisfied with this answer, or would you like this to become the reference issue for discussion of "eventually oK should probably use coroutines for everything"?

refi64 commented 9 years ago

@JohnEarnest It's fine, but I'm not sure what you mean by "coroutines for everything."

JohnEarnest commented 9 years ago

In JS, in a web browser, it is not possible to process input of any kind while code is running- the JS engine is a single thread per page (at best). Implementing something as simple as a "break" key to halt infinite loops would require this sort of input.

There is a way around this limitation if the interpreter were modified such that it periodically yielded to the browser to allow input events to be handled. Arbitrarily pausing and resuming the interpreter is not feasible currently because oK uses JavaScript's stack, recursively evaluating K expressions. With an entirely synthetic stack and a non-recursive interpreter (or using continuations, which are a mechanism for effectively achieving the same thing) it would be easy to process some number of "operations" and then return with a setTimeout() call to fire the interpreter up again after a brief pause.

The reason I haven't done this yet is it's horribly messy- you have to take it into consideration in every part of the interpreter, and it adds considerable complexity. I see relative simplicity and ease of understanding as a major goal in this project.

The MLogo interpreter I wrote is one illustration of the kind of "non-recursive interpreter" I'm describing here. In that case I went with that type of structure because I needed to support tail recursion and Java does not permit unsafe operations like stack-smashing to achieve it.