如何在F#中执行链式回调?

如何在F#中执行链式回调?,f#,asynchronous,tcplistener,F#,Asynchronous,Tcplistener,在C#中,我使用异步版本的TcpListener/TcpClient,并通过回调方法将它们链接起来,以便在回调完成时发布另一个Accept/Read。以下是一个示例(未经测试): 我的问题是如何在F#中模拟类似的东西?我会使用async关键字吗?是BeginAcceptTcpClient、BeginRead等后面的代码。。本质上是在回调函数中执行的代码?例如,这是正确的吗 let accept(listener:TcpListener) = async { let! client

在C#中,我使用异步版本的TcpListener/TcpClient,并通过回调方法将它们链接起来,以便在回调完成时发布另一个Accept/Read。以下是一个示例(未经测试):

我的问题是如何在F#中模拟类似的东西?我会使用async关键字吗?是BeginAcceptTcpClient、BeginRead等后面的代码。。本质上是在回调函数中执行的代码?例如,这是正确的吗

let accept(listener:TcpListener) = async {      
  let! client = listener.AsyncAcceptTcpClient()    
  // do something with the TcpClient such as beginning a Read chain
  accept(listener)
  return()
}    

上面的代码不起作用,因为没有定义accept,并且从技术上来说将其标记为recursive是不正确的,因为它不是递归方法?

我不确定您所说的“它不是递归方法”是什么意思;如果从函数本身的定义中引用函数,则它是一个递归函数。我对Sockets类没有太多的经验,但也许您正在寻找类似的东西

let rec accept(t : TcpListener) =
  async {
    let! client = t.AsyncAcceptTcpClient()

    // do some stuff with client here

    do! accept(t)
  }

@kvb的答案是正确的和惯用的

我还想指出,您可以使用(喘息)循环:

let accept(t:TcpListener)=
let completed=ref false
异步的{
当没有(!完成)时,请执行以下操作
let!client=t.asyncAcceptCpcClient()
如果客户端为空,则
废话(客户)
其他的
已完成:=真
}

(这是在我的浏览器中输入代码,希望它能编译)。这很好,因为你肯定不能在C代码中使用循环(必须跨越多个方法和begin/end回调)。

我想我的问题更多的是关于语义。C#等语言中的递归方法最终将导致堆栈溢出错误。在我的C代码示例中,它不是递归的,不会导致堆栈溢出。在F#中,“rec”关键字是否意味着它将以某种方式被递归调用,或者它只是向方法本身提供方法签名?我想我可以通过ildasm找到答案,但我很好奇是否有人知道。@esac:The
rec
关键字允许函数的定义引用函数本身。就编译策略而言,这可能会也可能不会导致生成递归方法(例如,单尾递归函数可能会编译成循环,而不是递归方法)。任何尾部递归方法的编译方式都应确保不会导致堆栈溢出(即使编译为递归方法,也会使用IL中的.tail指令防止溢出)。请注意,这对于VS2010中的发布模式是正确的,但可能不适用于调试模式;要避免这种情况,您需要同步检查ar.Completed并。。。啊。。。用C#做这件事真是噩梦。很高兴你有F:)但完整性方面,请参见完整正确的C代码。这确实很酷,尽管您提到的有点吓人:)
let rec accept(t : TcpListener) =
  async {
    let! client = t.AsyncAcceptTcpClient()

    // do some stuff with client here

    do! accept(t)
  }
let accept(t:TcpListener) =
    let completed = ref false 
    async {
        while not(!completed) do 
            let! client = t.AsyncAcceptTcpClient()
            if client <> null then
                Blah(client)
            else
                completed := true
    }