2

I wrote this piece of code with 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

And I got this error (on the last line, i.e. sock) :

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

Well, yes, sock is of type Lwt_unix.file_descr, why would the compiler throw this program and force the type 'a Lwt.t ? (when I ask what type was found for create_socket it tells me it's of type unit -> '_a)

P.S. : Thanks to Daniil Baturin : http://baturin.org/code/lwt-counter-server/

Lhooq
  • 4,281
  • 1
  • 18
  • 37
  • 1
    For first error, the compiler is most likely correlating against the call to the function. The call is expecting something other than a file descriptor. The type you report for `create_socket` (`unit -> 'a`) is inconsistent with the error message you report, so it's hard to comment on that. However, nothing has been forced to unit. The type of `create_socket` is `unit -> Lwt_unix.file_descr`. The `unit` is the input type (represented by `()` in your definition). – Jeffrey Scofield Jan 12 '17 at 16:16
  • 1
    I can't reproduce your warning in the second example. I pasted the code literally. – antron Jan 12 '17 at 16:28
  • It should also be noted that no type was inferred by the compiler for `create_socket`, because of the type error. The `'_a` is a unification variable from an intermediate stage of type inference. – antron Jan 12 '17 at 16:30
  • 1
    Woops, I miswrote ! I didn't understand the answers and then I read again my question and realised what I wrote. Question updated with the good type. – Lhooq Jan 12 '17 at 16:49
  • 1
    I removed the second part, I did some error with >> (I was using it with a unit on the right side) – Lhooq Jan 12 '17 at 16:54

1 Answers1

2

The compiler has not forced the type of the result to unit, it forced the type of the argument to unit because the argument pattern you have is ().

let%lwt is Lwt.bind, so the continuation (after the in) must evaluate to a promise (_ Lwt.t). Since sock is Lwt_unix.file_descr and not a promise, you must wrap it: Lwt.return sock.

More context might be needed to answer your question about the warning, I'm leaving you a comment.

antron
  • 3,749
  • 2
  • 17
  • 23
  • But what if I don't want it wrapped ? – Lhooq Jan 12 '17 at 16:39
  • If you really want to avoid wrapping it explicitly, you can use `Lwt_unix.Versioned.bind_2 sock sockaddr >|= fun () -> listen sock backlog; sock`, but the `>|=` effectively wraps it for you internally (actually, it's *very* slightly more efficient). – antron Jan 12 '17 at 16:47
  • No, I mean, what if I want to return sock of type Lwt_unix.file_descr and not something of type Lwt_unix.file_descr Lwt.t ? – Lhooq Jan 12 '17 at 16:50
  • 1
    You can't, at least not easily, and that's a type safety *feature* of Lwt. If you have `let%lwt foo = e in e'`, the computation started by `e` completes in the future. `e` has a promise type to let the type system know about that. But if `e` completes in the future, then `foo` only becomes available in the future, and so the computation started by `e'` that uses `foo` must also complete in the future. That means the whole `let%lwt` must evaluate to a promise, so a function that uses it is going to have a result type in `_ Lwt.t`. It tells callers that it doesn't complete right away. – antron Jan 12 '17 at 16:53
  • 1
    Thanks a lot, indeed this was the thing I didn't understand about promises. I used it like this `let () = Lwt_main.run (let%lwt sock = create_socket () in process_client sock)` which was the right thing to do, I guess. ;-) – Lhooq Jan 12 '17 at 16:55