Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Delay type #223

Merged
merged 40 commits into from
Oct 25, 2021
Merged

Delay type #223

merged 40 commits into from
Oct 25, 2021

Conversation

byorgey
Copy link
Member

@byorgey byorgey commented Oct 12, 2021

Make explicit in the type system when evaluation of a computation should be delayed. This gives the user fine-grained control over selective laziness (for example, once we have sum types and recursive types, one could use this to define lazy infinite data structures). It also allows us to guarantee that certain commands such as build and reprogram delay evaluation of their arguments, and lets the user e.g. define their own modified versions of build without compromising those guarantees.

  • Delay is indicated by curly braces both at the value and type levels, that is, if t : ty then {t} : {ty}.
  • force : {ty} -> ty is now exposed in the surface language.
  • Change from a CEK machine to a CESK machine. Recursive let and def delay via allocating a cell in the store. For now, there is no other way to allocate anything in the store, but see discussion at Error when wrapping build #150 for some possible future directions.
  • change the types of build and reprogram to require a delayed program, e.g. build : string -> {cmd a} -> cmd string
  • if and try also require delayed arguments.
  • don't elaborate Build and Reprogram with extra Delay wrappers since one is now required by the type
  • Division by zero, negative exponents, and bad comparisons now throw exceptions.

Closes #150. Closes #226.

- Add a new type constructor `delay`
- `TDelay` is now written with special double brackets `{{...}}`;
  `{{t}} : delay ty` whenever `t : ty`
- Add a special case to the parser: `{{}}` parses as `delay noop`
- `force : delay ty -> ty` is now written as a prefix `!`
  e.g. `{{5}} : delay int` and `!{{5}} : int`
- Change the types of `build` and `reprogram` to require a delayed program, e.g.
  `build : string -> delay (cmd a) -> cmd string`
- Don't elaborate `Build` and `Reprogram` with extra `Delay` wrappers
  since one is now required by the type
@byorgey byorgey requested a review from polux October 12, 2021 21:02
@byorgey
Copy link
Member Author

byorgey commented Oct 13, 2021

Once we're all on the same page re syntax etc, I will update the tutorial and example programs.

@polux
Copy link
Collaborator

polux commented Oct 13, 2021

This made me realize a few things and I'm wondering if we should do this at all. Adding my thoughts/questions to #150 so the conversation doesn't get fragmented.

@polux polux mentioned this pull request Oct 13, 2021
@xsebek xsebek mentioned this pull request Oct 13, 2021
Copy link
Collaborator

@polux polux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I only have a few nits.

I reviewed the PR because if I understand the github UI correctly you did request a review. But the step function is not modified yet. Is it because you'd like to stage the review? (Which is very much welcome if that is the case: it's always easier to review small chunks.) Or is it because you're planning on modifying the step function in a different PR?

@byorgey
Copy link
Member Author

byorgey commented Oct 15, 2021

@polux I think I requested a review when I initially opened the PR. I didn't specifically request one just now, but I appreciate the feedback, and you're right, reviewing in small chunks is helpful! I do plan to update the step function in this PR. Right now a store exists but is never used for anything.

@byorgey byorgey marked this pull request as ready for review October 23, 2021 02:45
@byorgey
Copy link
Member Author

byorgey commented Oct 23, 2021

I think this is ready for another round of review. Note that at the moment, all delays are non-memoizing except for recursive let bindings and all def bindings; there is no way for users to explicitly get memoization. Of course this is probably something we want to explore further, but based on the conversation in #150 it seems like there is a large design space to explore, so I just wanted to get something simple working here first.

@byorgey byorgey requested a review from polux October 23, 2021 02:50
@xsebek
Copy link
Member

xsebek commented Oct 23, 2021

Great work @byorgey! 👍

I will play with this some more, but the first thing I thought about was that it would be helpful to add the braces to F1 help:

┌─────────────────────────┬──────────────
│build <name> {<commands>}│Create a robot 

Could you please add a table of types, now that we have {a} and a+b?

@byorgey
Copy link
Member Author

byorgey commented Oct 23, 2021

Good ideas @xsebek , will do!

@byorgey
Copy link
Member Author

byorgey commented Oct 23, 2021

How do you think the table of types should fit with the rest of the help? If I just add another table horizontally they all get too narrow in a reasonably-sized terminal window.

@xsebek
Copy link
Member

xsebek commented Oct 24, 2021

Also it seems this fixes the wait cancellation 🥳 #194

@xsebek
Copy link
Member

xsebek commented Oct 24, 2021

I updated my list.sw and measured this with delay-type and on main:

branch testLIST with 8ticks/s testLIST with 1024ticks/s testLIST_BIG with 8ticks/s testLIST_BIG with 1024ticks/s
delay-type 58s >1s <1h 47s
main 1min 7s >1s <1h 49s

The improvement is small*, but it is there and all that matters is that it is not slower. 👍
*) Likely because I used the lazy values for more efficient headTail from which head is forced without computing tail.

There is a small bug with cancelling and then repeating a long computation, for example:

> let lbiggest = cons (2^2^21) $ cons (2^2^7) nil in len lbiggest // Ctrl-C
> let lbiggest = cons (2^2^21) $ cons (2^2^7) nil in len lbiggest
fatal error: Reference to unknown memory
  cell 16

But I don't think it is important enough to block this There is a more common but just as fatal example below. 🙁

@xsebek
Copy link
Member

xsebek commented Oct 24, 2021

@byorgey ad F1 help - I was thinking the table would be above commands, but it may need scrolling to fit in smaller terminals. Which is probably OK as it is focused and can use ⬇️ and ⬆️ .

We can leave that for another PR - with scrolling we could even list all available commands.

Copy link
Member

@xsebek xsebek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incredible work @byorgey! I think this is good to merge except for the problem with cancelling computation, which is unchecked and hopefully easy to fix. 🙂

@xsebek xsebek mentioned this pull request Oct 24, 2021
@byorgey byorgey linked an issue Oct 24, 2021 that may be closed by this pull request
@byorgey
Copy link
Member Author

byorgey commented Oct 24, 2021

You're right, it does fix #194, though I didn't realize I was fixing it. =) The bug previously was that we did Ctrl+C just by setting the robot's machine to idleMachine, but we did not actually put it back into the activeRobot set. Previously, the idleMachine actually had to execute a no-op instruction, but since it was not in the activeRobot set it never made progress executing this no-op instruction, and the REPL still thought it was doing something. But having idleMachine execute a no-op is silly; I changed it to be simply a CEK machine in a done state. Now it is correct to not add the robot to the activeRobot set, and the REPL immediately recognizes that the base is no longer doing anything.

@byorgey
Copy link
Member Author

byorgey commented Oct 24, 2021

Hmm, good catch re: Ctrl+C causing problems with memory cells. This is a bit tricky. When we hit Ctrl+C we set the base's machine to idleMachine, which is definitely no longer correct, because idleMachine has an empty store, so this just throws away any memory cells that were allocated. However, it would also not be correct to just leave the store the same and reset the other machine components, because we might be in the middle of evaluating a cell, which would therefore be set to a Blackhole. If we ever try to use it, the system will encounter the Blackhole and incorrectly complain about an infinite loop.

Perhaps the solution is that a Blackhole should save the original expression which is being evaluated; when we Ctrl+C, any Blackholes in the store should be reset.

Hmm, I discovered by accident that we can end up with stray Blackholes if an exception is thrown as well. So we'll need some more general mechanism for resetting them...

- Add functions `cancel` and `resetBlackholes` to reset the store
  properly
- Use those functions (1) when cancelling the base computation via
  Ctrl+C, or (2) when there is an uncaught exception
@byorgey
Copy link
Member Author

byorgey commented Oct 24, 2021

This ought to fix the issues with Ctrl+C and the store.

@byorgey byorgey requested a review from xsebek October 25, 2021 03:37
Copy link
Collaborator

@polux polux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I gave it a good look but couldn't find anything really meaningful to say.

-- body, binding the variable to a reference to the memory cell we
-- just allocated for the body expression itself. As a fun aside,
-- notice how Haskell's recursion and laziness play a starring
-- role: @loc@ is both an output from @allocate@ and used as part
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reminds me of "Assembly: Circular Programming with Recursive do" in https://wiki.haskell.org/wikiupload/1/14/TMR-Issue6.pdf :)

Copy link
Member

@xsebek xsebek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ought to fix the issues with Ctrl+C and the store.

I checked it out and it works perfectly! 🥳

@byorgey byorgey added the merge me Trigger the merge process of the Pull request. label Oct 25, 2021
@mergify mergify bot merged commit c982e81 into main Oct 25, 2021
@mergify mergify bot deleted the delay-type branch October 25, 2021 13:28
@byorgey byorgey mentioned this pull request Oct 28, 2021
@byorgey byorgey mentioned this pull request Jun 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge me Trigger the merge process of the Pull request.
Projects
None yet
3 participants