简体   繁体   中英

F# Continuous loop in F#

I have a socket server that needs to run on a loop accepting clients, so I found out that in funcional programming, a recursive loop is used:

let awaitConnections (wsl:WebSocketListener) = 
    let rec loop ()=
        async { 
            let! ws = Async.AwaitTask (wsl.AcceptWebSocketAsync(cancellation.Token) )
            printfn "Connection from %s" (ws.RemoteEndpoint.Address.ToString())
            Async.Start <| awaitMessages ws
            do! loop()}
    loop()

And this code is invoked by doing:

Async.Start <| awaitConnections listener

Considering that the app runs continuously, should I use a iterative approach instead? Does the rec approach creates nested execution stacks?

Also, I would like to do something after the loop ends, like:

let awaitConnections (wsl:WebSocketListener) = 
    let rec loop ()=
        async { 
            let! ws = Async.AwaitTask (wsl.AcceptWebSocketAsync(cancellation.Token) )
            printfn "Connection from %s" (ws.RemoteEndpoint.Address.ToString())
            Async.Start <| awaitMessages ws
            do! loop()}
    loop()
    printf "The loop ended" // <-- this line

But then it cannot compile because the awaitConnections return type. How could I do that? Am I doing this right?

You're certainly on the right track! Here is a simple example that demonstrates what you need to do:

// Loop that keeps running forever until an exception happens
let rec loop () = async {
  do! Async.Sleep(1000)
  printfn "Working"
  return! loop () }

// Call the loop in a try .. finally block to run some cleanup code at the end
let main () = async {
  try 
    do! loop () 
  finally 
    printfn "That's it!" }

// Start the work in the background and create a cancellation token
let cts = new System.Threading.CancellationTokenSource()
Async.Start(main (), cts.Token)
// To cancel it, just call: cts.Cancel()

A few important points:

  • You cannot really run code after an infinite loop finishes (it is infinite!) but you can use try .. finally to run some code when the block is cancelled

  • Note that using return! for recursive looping is better - using do! creates memory leaks.

  • You can cancel computation using cancellation token - just pass the token when starting it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM