caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Ben Millwood <bmillwood@janestreet.com>
To: Philippe Veber <philippe.veber@gmail.com>
Cc: caml users <caml-list@inria.fr>
Subject: Re: [Caml-list] Not letting channels escape.
Date: Fri, 8 Aug 2014 12:30:38 +0100	[thread overview]
Message-ID: <CA+MHO53k186F3cAAHdsKmxWEXFt-Qg0_B8eL5OvAkW1jZaDg2A@mail.gmail.com> (raw)
In-Reply-To: <CAOOOohRCFcHLsgkpVrknKcQG1asP6WwUwvwmMuZbPV72gitL+g@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 3023 bytes --]

There's a trick with existential types, as used in e.g. Haskell's ST monad.
It uses the fact that an existentially-quantified type variable can't
escape its scope, so if your channel type and results that depend on it are
parametrised by an existential type variable, the corresponding values
can't escape the scope of the callback either.

Something like:

module ST : sig
  type ('a, 's) t
  include Monad.S2 with type ('a, 's) t := ('a, 's) t
  type 's chan
  type 'a f = { f : 's . 's chan -> ('a, 's) t }
  val with_file : string -> f:'a f -> 'a

  val input_line : 's chan -> (string option, 's) t
end = struct
  module T = struct
    type ('a, 's) t = 'a
    let return x = x
    let bind x f = f x
    let map x ~f = f x
  end
  include T
  include Monad.Make2(T)
  type 's chan = In_channel.t
  type 'a f = { f : 's . 's chan -> ('a, 's) t }
  let with_file fp ~f:{ f } = In_channel.with_file fp ~f
  let input_line c = In_channel.input_line c
end
;;

match ST.with_file "safe.ml" ~f:{ ST.f = fun c -> ST.input_line c } with
| None -> print_endline "None"
| Some line -> print_endline line


On 8 August 2014 11:23, Philippe Veber <philippe.veber@gmail.com> wrote:

> Dear all,
>
> many libraries like lwt, batteries or core provide a very nice idiom to be
> used when a function uses a resource (file, connection, mutex, et cetera),
> for instance in Core.In_channel, the function:
>
> val with_file : ?binary:bool -> string -> f:(t -> 'a) -> 'a
>
> opens a channel for [f] and ensures it is closed after the call to [f],
> even if it raises an exception. So these functions basically prevent from
> leaking resources. They fail, however, to prevent a user from using the
> resource after it has been released. For instance, writing:
>
> input_char (In_channel.with_file fn (fun x -> x))
>
> is perfectly legal type-wise, but will fail at run-time. There are of
> course less obvious situations, for instance if you define a function:
>
> val lines : in_channel -> string Stream.t
>
> then the following will also fail:
>
> Stream.iter f (In_channel.with_file fn lines)
>
> My question is the following: is there a way to have the compiler check
> resources are not used after they are closed? I presume this can only be
> achieved by strongly restricting the kind of function passed to
> [with_file]. One simple restriction I see is to define a type of immediate
> value, that roughly correspond to "simple" datatypes (no closures, no lazy
> expressions):
>
> module Immediate : sig
>   type 'a t = private 'a
>   val int : int -> int t
>   val list : ('a -> 'a t) -> 'a list -> 'a list t
>   val tuple : ('a -> 'a t) -> ('b -> 'b t) -> ('a * 'b) -> ('a * 'b) t
>   (* for records, use the same trick than in
> http://www.lexifi.com/blog/dynamic-types *)
>   ...
> end
>
> and have the type of [with_file] changed to
>
> val with_file : string -> f:(in_channel -> 'a Immediate.t) -> 'a
>
> I'm sure there are lots of smarter solutions out there. Would anyone
> happen to know some?
>
> Cheers,
>   Philippe.
>
>

[-- Attachment #2: Type: text/html, Size: 4001 bytes --]

  parent reply	other threads:[~2014-08-08 11:30 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-08 10:23 Philippe Veber
2014-08-08 11:22 ` Peter Zotov
2014-08-08 11:30 ` Ben Millwood [this message]
2014-08-08 14:49   ` Ben Millwood
2014-08-08 15:44     ` Markus Mottl
2014-08-08 16:01       ` Ben Millwood
2014-08-08 17:21         ` Markus Mottl
2014-08-08 17:37           ` Gabriel Scherer
2014-08-08 18:23             ` Markus Mottl
2014-08-08 18:28               ` Frédéric Bour
2014-08-08 19:30                 ` Markus Mottl
2014-08-08 19:45                   ` Frédéric Bour
2014-08-08 20:34                     ` Markus Mottl
2014-08-10 18:06                       ` Philippe Veber
2014-08-11  9:07                     ` Ben Millwood
2014-08-11 15:26                       ` Goswin von Brederlow

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CA+MHO53k186F3cAAHdsKmxWEXFt-Qg0_B8eL5OvAkW1jZaDg2A@mail.gmail.com \
    --to=bmillwood@janestreet.com \
    --cc=caml-list@inria.fr \
    --cc=philippe.veber@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).