Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you implement goto in F#?

Tags:

f#

goto

All my favorite languages have a goto command. That is, you can create a label, and then later interrupt the flow of the program to go to the label. One of the more useful applications of this construct is to create an infinite loop, like this:

 start:
 goto start

Unfortunately, if I undertstand the compiler errors correctly, I can't use this same syntax in F#. So, since it doesn't seem to be supported natively, how can I implement the goto command in F#?

Surely, F# is a powerful enough language to implement a feature as simple as this. Other languages, such as Javascript, which do not natively support goto, are still able to implement it through a plug-in.

Further, I feel that F#, as one of the languages in the functional programming paradigm, should be able to support higher-level gotos: where you can pass gotos to gotos.

like image 334
Peter Olson Avatar asked Aug 19 '11 21:08

Peter Olson


2 Answers

A label has a lot in common with a function: they both act as entry points to some code to be executed. Given that similarity, you can do the following:

let goto f = f()

let test() =
  let label = (fun () ->
    //rad code
    )
  //tight code
  goto label

One minor drawback is having to wrap all your code in closures. I don't know--doesn't seem too bad for getting something as handy as goto.

like image 101
Daniel Avatar answered Oct 03 '22 13:10

Daniel


You can get the behavior of a GOTO in F# with mutually recursive functions. Tail call optimization allows for this goto nature and doesn't push anything onto the stack.

int parse() 
{
    Token   tok;

reading:
    tok = gettoken();
    if (tok == END)
        return ACCEPT;
shifting:
    if (shift(tok))
        goto reading;
reducing:
    if (reduce(tok))
        goto shifting;
    return ERROR;
}

Here do_read, do_shift and re_reduce act as labels.

type Token = END | SOMETHINGELSE

type Status = ACCEPT | ERROR

let parse gettoken shift reduce () =
    let rec do_read() =
        match gettoken() with
        | END -> ACCEPT
        | _ as tok -> do_shift tok

    and do_shift tok =
        if shift tok then
            do_read()
        else
            do_reduce tok

    and do_reduce tok =
        if reduce tok then
            do_shift tok
        else
            ERROR

    do_read()

Code source http://sharp-gamedev.blogspot.com/2011/08/forgotten-control-flow-construct.html

like image 24
gradbot Avatar answered Oct 03 '22 15:10

gradbot