14

A usual pattern for CLI application is to run in infinite loop, until user types some quit command. Like, in C language:

while(1){
scanf("%c", &op);
    ...
    else if(op == "q")
        break;
    }

What would be the pattern for such console application in F# (tried to use tail recursrion, but failed)?

Arnthor
  • 2,563
  • 6
  • 34
  • 54

4 Answers4

11

Typing in browser, thus may contain errors:

let rec main() = 
    let c = System.Console.ReadKey()
    if c.Key = System.ConsoleKey.Q then () // TODO: cleanup and exit
    else 
    // TODO: do something in main
    main()
desco
  • 16,642
  • 1
  • 45
  • 56
11

Here's a none blocking version that responds to single key press.

open System

let rec main() = 
    // run code here

    // you may want to sleep to prevent 100% CPU usage
    // Threading.Thread.Sleep(1);

    if Console.KeyAvailable then
        match Console.ReadKey().Key with
        | ConsoleKey.Q -> ()
        | _ -> main()
    else
        main()

main()
gradbot
  • 13,732
  • 5
  • 36
  • 69
  • May want a `Sleep(0)` or `SwitchToThread()` in the `else` or that will be a high CPU usage loop. :-] – ildjarn Apr 16 '12 at 18:17
  • 1
    Wouldn't this eventually cause a stack overflow? – nphx Jul 26 '14 at 23:07
  • 3
    @nphx F# supports tail recursion. This allows recursive code to be written in F# that won't overflow and is just as fast as looped version. Try searching for "F# tail recursion". – gradbot Jul 27 '14 at 04:49
  • @gradbot Being new to the functional world I was not aware of that concept. Cool. – nphx Jul 27 '14 at 09:09
6

Such a function can be useful:

let rec forever f = 
  f()
  forever f

Usage:

forever <| fun () ->
  //function body

A more literal translation of your code, however, would be:

while true do
  //body
Daniel
  • 47,404
  • 11
  • 101
  • 179
4

Also

while true do
    (* ..code.. *)

But I guess tail-recursion is more fancy (they'll both compile to the same thing under --optimize).

Ramon Snir
  • 7,520
  • 3
  • 43
  • 61