What is usually abstracted about IO
is the monad and the common definition of the IO
is:
type 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
val return : 'a -> 'a t
Then, some libraries (eg. ocaml-cohttp
or ocaml-git
) use some syscall which use this monad. However, systematically functorize your code over this monad is not systematically good. Some others libraries prefer to define their own monad (I’m not sure to use this term in this case) which returns specific action. Then, they let the user to plug which syscall he wants to use from these actions. They are completely free from the monad and they can take some specific advantages specific to Async
or Lwt
. Like ocaml-tls
, decompress
or angstrom
:
type t
val handle : t -> [ `Read of bytes | `Write of string | `Done ]
Some others, through, want to call a syscall at a specific time of the process - but they want to be free from the io
used and they don’t want to use a functor. It’s another pattern which is start to be used by the MirageOS in some specific contexts:
type ('a, 's) io
type 's scheduler =
{ bind : 'a 'b. ('a, 's) io -> ('a -> ('b, 's) io) -> ('b, 's) io
; return : 'a. 'a -> ('a, 's) io }
type ('resolver, 's) gethostbyname = 'resolver -> domain -> (ipv4, 's) io
val connect : 's scheduler -> ('r, 's) gethostbyname -> 'r -> socket -> (socket, 's) io
An other case exists to plug a given implementation under a used interface at the link time. By this way, a library can use a concrete module and we can specialize it with a specific implementation (unix
, lwt
or async
) but we never tried this pattern.
From what I know, definition given by dune
for example about Future
is good but, again, it’s not a systematic solution when some others patterns can fit better on your case (depending on what you want to provide). MirageOS has an interesting story about all of that because we tried to see which pattern can scale for some big projects.
My opinion is to say that any of these patterns can not be used largely for our purposes. At least, we should document them but a magic solution like a module type FUTURE
should not be the only solution.