Ошибка типа LWT 2.7.0

Я написал этот фрагмент кода с Lwt 2.7.0:

open Lwt

let listen_address = Unix.inet_addr_loopback
let port = 9000
let backlog = 1

let () = Lwt_log.add_rule "*" Lwt_log.Info

let create_socket () =
  let open Lwt_unix in
  let sock = socket PF_INET SOCK_STREAM 0 in
  let sockaddr = ADDR_INET(listen_address, port) in
  let%lwt () = Lwt_unix.Versioned.bind_2 sock sockaddr in
  listen sock backlog;
  sock

И я получил эту ошибку (в последней строке, т.е. sock):

Error: This expression has type Lwt_unix.file_descr
       but an expression was expected of type 'a Lwt.t

Ну да, sock относится к типу Lwt_unix.file_descr, зачем компилятору бросать эту программу и форсировать тип 'a Lwt.t? (когда я спрашиваю, какой тип был найден для create_socket, мне говорят, что это тип unit -> '_a)

P.S. : Спасибо Даниилу Батурину : http://baturin.org/code/lwt-counter-server/


person Lhooq    schedule 12.01.2017    source источник
comment
Для первой ошибки компилятор, скорее всего, коррелирует с вызовом функции. Вызов ожидает чего-то другого, кроме файлового дескриптора. Тип, который вы сообщаете для create_socket (unit -> 'a), не соответствует сообщению об ошибке, которое вы сообщаете, поэтому трудно комментировать это. Однако ничто не было принуждено к объединению. Тип create_socketunit -> Lwt_unix.file_descr. unit — это тип ввода (представленный () в вашем определении).   -  person Jeffrey Scofield    schedule 12.01.2017
comment
Я не могу воспроизвести ваше предупреждение во втором примере. Я вставил код буквально.   -  person antron    schedule 12.01.2017
comment
Следует также отметить, что компилятор не вывел тип для create_socket из-за ошибки типа. '_a — это унифицирующая переменная промежуточного этапа вывода типа.   -  person antron    schedule 12.01.2017
comment
Упс, я неправильно написал! Я не понял ответов, а потом перечитал свой вопрос и понял, что написал. Вопрос обновлен с хорошим типом.   -  person Lhooq    schedule 12.01.2017
comment
Вторую часть удалил, ошибся с ›› (использовал с единицей справа)   -  person Lhooq    schedule 12.01.2017


Ответы (1)


Компилятор не задает тип результата unit, он задает тип аргумента unit, потому что у вас есть шаблон аргумента ().

let%lwt равно Lwt.bind, поэтому продолжение (после in) должно оцениваться как обещание (_ Lwt.t). Поскольку sock — это Lwt_unix.file_descr, а не обещание, вы должны обернуть его: Lwt.return sock.

Чтобы ответить на ваш вопрос о предупреждении, может потребоваться дополнительный контекст, я оставляю вам комментарий.

person antron    schedule 12.01.2017
comment
Но что, если я не хочу, чтобы это было завернуто? - person Lhooq; 12.01.2017
comment
Если вы действительно хотите избежать его явной обертки, вы можете использовать Lwt_unix.Versioned.bind_2 sock sockaddr >|= fun () -> listen sock backlog; sock, но >|= эффективно обертывает его для вас внутри (на самом деле, это очень немного эффективнее). - person antron; 12.01.2017
comment
Нет, я имею в виду, что если я хочу вернуть sock типа Lwt_unix.file_descr, а не что-то типа Lwt_unix.file_descr Lwt.t? - person Lhooq; 12.01.2017
comment
Вы не можете, по крайней мере, не легко, и это особенность безопасности типов Lwt. Если у вас есть let%lwt foo = e in e', вычисления, начатые e, завершатся в будущем. e имеет тип обещания, чтобы система типов знала об этом. Но если e завершится в будущем, то foo станет доступным только в будущем, поэтому вычисление, начатое e' и использующее foo, также должно завершиться в будущем. Это означает, что весь let%lwt должен оцениваться как обещание, поэтому функция, которая его использует, будет иметь тип результата в _ Lwt.t. Он сообщает вызывающим абонентам, что не завершается сразу. - person antron; 12.01.2017
comment
Большое спасибо, действительно, это было то, чего я не понимал в обещаниях. Я использовал это так let () = Lwt_main.run (let%lwt sock = create_socket () in process_client sock), что, я думаю, было правильным. ;-) - person Lhooq; 12.01.2017