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

Constructs for non-sequential control flow #37

Open
j-hui opened this issue Oct 25, 2021 · 4 comments
Open

Constructs for non-sequential control flow #37

j-hui opened this issue Oct 25, 2021 · 4 comments

Comments

@j-hui
Copy link
Contributor

j-hui commented Oct 25, 2021

I just realized that so far we haven't added return into the parser yet... It's not totally clear cut to me how this should be done, so I wanted to write down a few thoughts/propose some ideas here.

I think we should make return a layout keyword, and parse for 'return' '{' expr '}'. This looks odd at first, and is not what I had in mind, but here is why I don't like the alternatives where it isn't a layout keyword, and return expressions are strictly concatenative:

  • If return is at the same precedence as application (juxtaposition), writing return f x is a type error, so if we are forced to write return (f x) or return $ f x. I think it should be at a higher precedence compared to other atomic expressions because something like f return shouldn't make any sense.
  • If return is magically at a higher precedence than application (juxtaposition), something like return return a b becomes ambiguous.

What are people's thoughts?

@sedwards-lab
Copy link
Contributor

Do we need one? I had hoped that the last thing in a block would be the return value (i.e., like Ocaml's ; operator) I realize that's not Monad-friendly, but I'm not sure we need to go that far.

@j-hui
Copy link
Contributor Author

j-hui commented Oct 29, 2021

The return I'm talking about here is distinct from Haskell's monadic return. What I'm suggesting here would be like break; an expression that halts control flow.

I would like to write:

waitSome (o: &(Option a)) -> a =
  loop
    wait o
    match o with
      Some a => return a
      _ => ()

I know we eventually want some better syntax for this kind of thing, but I would also like to write this directly (i.e., I think this is what it should desugar down to). The alternatives, without a return statement, are to have some kind of uninitialized value:

waitSomeUninit (o: &(Option a)) -> a =
  let a = new ?? // declare withou initialization?
  loop
    wait o
    match o with
      Some a' => a <- a' ; break
      _ => ()
  deref a

Or some kind of unsafe match:

waitSomeMatchTwice (o: &(Option a)) -> a =
  loop
    wait o
    match o with
      Some a => break
      _ => ()

  match o with
    Some a => a
    _ => undefined // should be unreachable, but feels very clunky and unnecessary

@sedwards-lab
Copy link
Contributor

I see. I think this is the tip of a more complicated iceburg that is "what sort of control-flow constructs should we support?"

In some sense, the example you've written are more like mid-test loops, which is a very interesting form of control-flow, something like

loop
  ...
  until expr
  ...

or just something like

loop
  ...
  if expr then break
  ...

Java eschews gotos for named loops and breaks. Esterel has an even more complicated mechanism where blocks of code may be started and terminated from both outside and from within (through exceptions).

My feeling is that traditional C-like return is rather a blunt instrument in our setting (which function are you returning from, exactly?).

@j-hui
Copy link
Contributor Author

j-hui commented Oct 29, 2021

Yeah, I was trying to write a more complicated example earlier when I realized that having a return inside of a closure makes it somewhat ambiguous exactly what is returning. Return is indeed insufficient.

I do really like the idea of named loops/breaks; a further extension of this is to have breaks take an expression, so I can do this kind of thing:

let x = loop // inlined waitSome behavior
          wait o
          match o
            Some a => break a
            _ => ()

So this just strictly a control flow issue; perhaps the question isn't just "where do I want control to go", but "what value do I want to give to the parent construct once I terminate it (whether that be a loop, closure, par, or wait)".

@j-hui j-hui changed the title Syntax for return Constructs for non-sequential control flow Oct 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants