Как сделать цепочечные обратные вызовы в F#?
В C# я использую асинхронные версии TcpListener/TcpClient и объединяю их в цепочку с помощью метода обратного вызова, чтобы после завершения обратного вызова было опубликовано другое сообщение Accept/Read. Вот пример (не проверено):
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 3000);
listener.Start();
PostAccept(listener);
}
private void PostAccept(TcpListener listener)
{
listener.BeginAcceptTcpClient(AcceptCallback, listener);
}
private void AcceptCallback(IAsyncResult ar)
{
var listener = ar.AsyncState as TcpListener;
if (listener == null)
{
return;
}
// get the TcpClient and begin a read chain in a similar manner
PostAccept(listener);
}
У меня вопрос, как мне моделировать что-то подобное в 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 не определен, а техническая маркировка его рекурсивно неверна, так как это не рекурсивный метод?
2 ответа
Я не уверен, что вы имеете в виду под "это не рекурсивный метод"; если вы ссылаетесь на функцию из ее собственного определения, то это рекурсивная функция. У меня нет большого опыта работы с классами 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
async {
while not(!completed) do
let! client = t.AsyncAcceptTcpClient()
if client <> null then
Blah(client)
else
completed := true
}
(это было набирать код в моем браузере, надеюсь, он компилируется). Это хорошо, так как вы, конечно, не можете использовать цикл в коде C# (который должен охватывать несколько методов с помощью обратных вызовов begin/end).