From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@sympa.inria.fr Delivered-To: caml-list@sympa.inria.fr Received: from mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by sympa.inria.fr (Postfix) with ESMTPS id AA5A27EEF8 for ; Tue, 11 Aug 2015 13:33:22 +0200 (CEST) Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of bmillwood@janestreet.com) identity=pra; client-ip=38.105.200.112; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="bmillwood@janestreet.com"; x-sender="bmillwood@janestreet.com"; x-conformance=sidf_compatible Received-SPF: Pass (mail3-smtp-sop.national.inria.fr: domain of bmillwood@janestreet.com designates 38.105.200.112 as permitted sender) identity=mailfrom; client-ip=38.105.200.112; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="bmillwood@janestreet.com"; x-sender="bmillwood@janestreet.com"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of postmaster@mxout1.mail.janestreet.com) identity=helo; client-ip=38.105.200.112; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="bmillwood@janestreet.com"; x-sender="postmaster@mxout1.mail.janestreet.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A0CSBQCN3MlVnHDIaSZdg29pBoMeaYEgqAaPeYI4hCCBWQKBLwdMAQEBAQEBEgEBAQEBBhYJT4QjAQEBAwESEQQZAQEsCwEECwkCCw0NHQICIQESAQUBChIGExIQh3cDCggDCps1jz+BLz4xik9xhGUBBYtqAwoVhTEBAQEBAQEBAwEBAQEBAQEBAQESBgqLR4JPHoIYBAeCaYFDhW4MjxuFBIV6gWyCD5BIhWcSI4EXEQaBcIIecAGCSwEBAQ X-IPAS-Result: A0CSBQCN3MlVnHDIaSZdg29pBoMeaYEgqAaPeYI4hCCBWQKBLwdMAQEBAQEBEgEBAQEBBhYJT4QjAQEBAwESEQQZAQEsCwEECwkCCw0NHQICIQESAQUBChIGExIQh3cDCggDCps1jz+BLz4xik9xhGUBBYtqAwoVhTEBAQEBAQEBAwEBAQEBAQEBAQESBgqLR4JPHoIYBAeCaYFDhW4MjxuFBIV6gWyCD5BIhWcSI4EXEQaBcIIecAGCSwEBAQ X-IronPort-AV: E=Sophos;i="5.15,652,1432591200"; d="scan'208";a="142516360" Received: from mxout1.mail.janestreet.com ([38.105.200.112]) by mail3-smtp-sop.national.inria.fr with ESMTP/TLS/DHE-RSA-AES256-SHA; 11 Aug 2015 13:33:21 +0200 Received: from tot-qpr-mailcore2.delacy.com ([172.27.56.106] helo=tot-qpr-mailcore2) by mxout1.mail.janestreet.com with esmtps (TLSv1:DHE-RSA-AES256-SHA:256) (Exim 4.82) (envelope-from ) id 1ZP7nz-0005gq-Me for caml-list@inria.fr; Tue, 11 Aug 2015 07:33:19 -0400 X-JS-Flow: external Received: by tot-qpr-mailcore2 with JS-mailcore (0.1) (envelope-from ) id BVyd1_-AAAHtD-Ue; 2015-08-11 07:33:19.656248-04:00 Received: from mail-la0-f41.google.com ([209.85.215.41]) by mxgoog1.mail.janestreet.com with esmtps (UNKNOWN:AES128-GCM-SHA256:128) (Exim 4.72) (envelope-from ) id 1ZP7nz-000202-Bb for caml-list@inria.fr; Tue, 11 Aug 2015 07:33:19 -0400 Received: by labd1 with SMTP id d1so55600978lab.1 for ; Tue, 11 Aug 2015 04:33:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=janestreet.com; s=google; h=mime-version:in-reply-to:references:from:date:message-id:subject:to :cc:content-type; bh=Zbke5vpbrZbHQ/L3XyiJSuWoJB2iSRMpr5qnQSZsam0=; b=WlXi5RvRkTLMipvm93h0YdxfYNpffn7SnF1XtQVLCNi6cXN993CBsCq5akP1BjGR2L Kf8CkTWcFvK8LMt3TQDjYj8XpOHo795ASNzYUOz5K9Egqmc0DrtJV3GQ9xiJH06dHz+G tofpAZSGdgFU0nVQQ20hOwJeXGz0x5A+0h6f0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc:content-type; bh=Zbke5vpbrZbHQ/L3XyiJSuWoJB2iSRMpr5qnQSZsam0=; b=mUfKMow0l/WpiaBfwXWEIi1RZYNOD+20XhqgU0//GDH+FKh7FcHUgJtg+SGqraCq10 XtjCxjsO7mBiR1ptymEONFA7rgq6grVtnU/+pWiE9CN3SjlUzpR/vr2/GfzAkfPJv6br TtSS/yaQwlJawg2VW7od2PVpXASQ6Gf1m3xyCXvjU7RWiMslPEAYvoee52Agiq+sv2QV 8ggMi1deA4NimoATNy0Ag4aH9On/uDK7m1LFDJLjgn91/1eI6ZclrftqjCk74R0k/RTn E9xK7/pPWyfW6rtca1OGC/2nfxGwEnFDEquPtWm0rbJEa00PRqynsv78NMK3ajIVUn9c 8wLg== X-Gm-Message-State: ALoCoQkBh65Ms5AEGWw2rUtq+Lc3OELRbnzjUWF6O+ZqpQz/ec8RsKQfyVegPk7W3Vaw9dGHqK3zdXVdOJ8utUwSMYxaZ7d19+eS5z/2QkQvxioozXhsbWQv+5Msq2l9OVsURQ58I6zc X-Received: by 10.152.87.52 with SMTP id u20mr25650349laz.48.1439292798331; Tue, 11 Aug 2015 04:33:18 -0700 (PDT) X-Received: by 10.152.87.52 with SMTP id u20mr25650338laz.48.1439292798218; Tue, 11 Aug 2015 04:33:18 -0700 (PDT) MIME-Version: 1.0 Received: by 10.25.216.133 with HTTP; Tue, 11 Aug 2015 04:32:57 -0700 (PDT) In-Reply-To: References: <20150806094030.GE16477@frosties> <864mkcci29.fsf@gmail.com> <20150811093625.GA5949@frosties> From:Ben Millwood Date: Tue, 11 Aug 2015 12:32:57 +0100 Message-ID: To:Gabriel Scherer Cc:Goswin von Brederlow , Malcolm Matalka , Nicolas Ojeda Bar , caml users Content-Type: multipart/alternative; boundary=001a11c3512af756c0051d0777d7 X-JS-Processed-by: mailcore Subject: Re: [Caml-list] Destructive use of file descriptors --001a11c3512af756c0051d0777d7 Content-Type: text/plain; charset=UTF-8 See also the following thread last year, "Not letting channels escape", which (after some incomplete attempts from me) illustrates a fully safe with_file function. https://sympa.inria.fr/sympa/arc/caml-list/2014-08/msg00024.html On 11 August 2015 at 12:14, Gabriel Scherer wrote: > > Yeah. I was thinking that that might be avoided. Something on the line > > of putting the file descriptor into a local module so ocaml would > > complain about it escaping its scope or something. > > You can use the "ST monad" trick to track escape of values or effects: > "Region-based resource management", Oleg > http://okmij.org/ftp/Haskell/regions.html > > However, this requires writing the resource-manipulating operations in > monadic style. > > module ST : sig > type ('s, 'a) st > val return : 'a -> ('s, 'a) st > val bind : ('a -> ('s, 'b) st) -> ('s, 'a) st -> ('s, 'b) st > > type ('s, 'a) st_ref > val st_ref : 'a -> ('s, ('s, 'a) st_ref) st > val get : ('s, 'a) st_ref -> ('s, 'a) st > val set : ('s, 'a) st_ref -> 'a -> ('s, unit) st > > type 'a secretive = { run : 's . unit -> ('s, 'a) st } > val run_st : 'a secretive -> 'a > end = struct > type ('s, 'a) st = 'a > let return x = x > let bind f m = f m > > type ('s, 'a) st_ref = 'a ref > let st_ref, get, set = ref, (!), (:=) > > type 'a secretive = { run : 's . unit -> ('s, 'a) st } > let run_st st = st.run () > end > > let (>>=) m f = ST.bind f m > > > > # let test = > ST.run_st { ST.run = fun () -> > ST.st_ref 1 >>= fun r -> > ST.get r >>= fun before -> > ST.set r 2 >>= fun () -> > ST.get r >>= fun after -> > ST.return (before + after) > };; > val test : int = 3 > > # let test_escape_1 = > ST.run_st { ST.run = fun () -> > ST.st_ref 1 >>= fun r -> > ST.return r > };; > Error: This field value has type unit -> ('a, ('a, int) ST.st_ref) ST.st > which is less general than 'b. unit -> ('b, 'c) ST.st > > # let test_escape_2 = > let hole = ref None in > ST.run_st { ST.run = fun () -> > ST.st_ref 1 >>= fun r -> > hole := Some r; > ST.return () > }; > !hole;; > Error: This field value has type unit -> ('a, unit) ST.st > which is less general than 'b. unit -> ('b, 'c) ST.st > > > On Tue, Aug 11, 2015 at 11:36 AM, Goswin von Brederlow > wrote: > > On Thu, Aug 06, 2015 at 07:50:38PM +0000, Malcolm Matalka wrote: > >> Nicolas Ojeda Bar writes: > >> > >> > Hi, > >> > > >> > No magic needed in OCaml: > >> > > >> > let with_open path f = > >> > let oc = open_out path in > >> > match f oc with > >> > | x -> close_out_noerr oc; x > >> > | exception e -> close_out_noerr oc; raise e > >> > > >> > and then use it as > >> > > >> > with_open "foo" (fun oc -> output_string oc str) > >> > > >> > Cheers > >> > > >> > Nicolas > >> > > >> > >> The weakness with this (which I'm not sure if Python offers protection) > >> is returning something that references the file created. It can lead to > >> some confusing error messages. > > > > Yeah. I was thinking that that might be avoided. Something on the line > > of putting the file descriptor into a local module so ocaml would > > complain about it escaping its scope or something. > > > > At least unlike the other suggestion this one closes the FD on exception. > > > > MfG > > Goswin > > > > -- > > Caml-list mailing list. Subscription management and archives: > > https://sympa.inria.fr/sympa/arc/caml-list > > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > > Bug reports: http://caml.inria.fr/bin/caml-bugs > > -- > Caml-list mailing list. Subscription management and archives: > https://sympa.inria.fr/sympa/arc/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs > --001a11c3512af756c0051d0777d7 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable
See also the following thread last year, "Not letting= channels escape", which (after some incomplete attempts from me) illu= strates a fully safe with_file function.


On 11 August 2015 at = 12:14, Gabriel Scherer <gabriel.scherer@gmail.com> w= rote:
> Yeah. I was t= hinking that that might be avoided. Something on the line
> of putting the file descriptor into a local module so ocaml would
> complain about it escaping its scope or something.

You can use the "ST monad" trick to track escape of values= or effects:
=C2=A0 "Region-based resource management", Oleg
=C2=A0 http://okmij.org/ftp/Haskell/regions.html

However, this requires writing the resource-manipulating operations in
monadic style.

module ST : sig
=C2=A0 type ('s, 'a) st
=C2=A0 val return : 'a -> ('s, 'a) st
=C2=A0 val bind : ('a -> ('s, 'b) st) -> ('s, 'a)= st -> ('s, 'b) st

=C2=A0 type ('s, 'a) st_ref
=C2=A0 val st_ref : 'a -> ('s, ('s, 'a) st_ref) st
=C2=A0 val get : ('s, 'a) st_ref -> ('s, 'a) st
=C2=A0 val set : ('s, 'a) st_ref -> 'a -> ('s, unit) = st

=C2=A0 type 'a secretive =3D { run : 's . unit -> ('s, '= a) st }
=C2=A0 val run_st : 'a secretive -> 'a
end =3D struct
=C2=A0 type ('s, 'a) st =3D 'a
=C2=A0 let return x =3D x
=C2=A0 let bind f m =3D f m

=C2=A0 type ('s, 'a) st_ref =3D 'a ref
=C2=A0 let st_ref, get, set =3D ref, (!), (:=3D)

=C2=A0 type 'a secretive =3D { run : 's . unit -> ('s, '= a) st }
=C2=A0 let run_st st =3D st.run ()
end

let (>>=3D) m f =3D ST.bind f m



# let test =3D
=C2=A0 =C2=A0 ST.run_st { ST.run =3D fun () ->
=C2=A0 =C2=A0 =C2=A0 ST.st_ref 1 >>=3D fun r ->
=C2=A0 =C2=A0 =C2=A0 ST.get r >>=3D fun before ->
=C2=A0 =C2=A0 =C2=A0 ST.set r 2 >>=3D fun () ->
=C2=A0 =C2=A0 =C2=A0 ST.get r >>=3D fun after ->
=C2=A0 =C2=A0 =C2=A0 ST.return (before + after)
=C2=A0 =C2=A0 };;
val test : int =3D 3

# let test_escape_1 =3D
=C2=A0 =C2=A0 ST.run_st { ST.run =3D fun () ->
=C2=A0 =C2=A0 =C2=A0 ST.st_ref 1 >>=3D fun r ->
=C2=A0 =C2=A0 =C2=A0 ST.return r
=C2=A0 =C2=A0 };;
Error: This field value has type unit -> ('a, ('a, int) ST.st_re= f) ST.st
=C2=A0 which is less general than 'b. unit -> ('b, 'c) ST.st=

# let test_escape_2 =3D
=C2=A0 =C2=A0 let hole =3D ref None in
=C2=A0 =C2=A0 ST.run_st { ST.run =3D fun () ->
=C2=A0 =C2=A0 =C2=A0 ST.st_ref 1 >>=3D fun r ->
=C2=A0 =C2=A0 =C2=A0 hole :=3D Some r;
=C2=A0 =C2=A0 =C2=A0 ST.return ()
=C2=A0 =C2=A0 };
=C2=A0 =C2=A0 !hole;;
Error: This field value has type unit -> ('a, unit) ST.st
=C2=A0 which is less general than 'b. unit -> ('b, 'c) ST.st=


On Tue, Aug 11, 2015 at 11:36 AM, Goswin von Brederlow
<goswin-v-b@web.de> wrote: > On Thu, Aug 06, 2015 at 07:50:38PM +0000, Malcolm Matalka wrote:
>> Nicolas Ojeda Bar <n.oje= .bar@gmail.com> writes:
>>
>> > Hi,
>> >
>> > No magic needed in OCaml:
>> >
>> >=C2=A0 =C2=A0let with_open path f =3D
>> >=C2=A0 =C2=A0 =C2=A0let oc =3D open_out path in
>> >=C2=A0 =C2=A0 =C2=A0match f oc with
>> >=C2=A0 =C2=A0 =C2=A0| x -> close_out_noerr oc; x
>> >=C2=A0 =C2=A0 =C2=A0| exception e -> close_out_noerr oc; ra= ise e
>> >
>> > and then use it as
>> >
>> >=C2=A0 =C2=A0with_open "foo" (fun oc -> output_st= ring oc str)
>> >
>> > Cheers
>> >
>> > Nicolas
>> >
>>
>> The weakness with this (which I'm not sure if Python offers pr= otection)
>> is returning something that references the file created.=C2=A0 It = can lead to
>> some confusing error messages.
>
> Yeah. I was thinking that that might be avoided. Something on the line=
> of putting the file descriptor into a local module so ocaml would
> complain about it escaping its scope or something.
>
> At least unlike the other suggestion this one closes the FD on excepti= on.
>
> MfG
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0Goswin
>
> --
> Caml-list mailing list.=C2=A0 Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group= /ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs

--
Caml-list mailing list.=C2=A0 Subscription management and archives:
https://sympa.inria.fr/sympa/arc/caml-list
Beginner's list: http://groups.yahoo.com/group/ocam= l_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

--001a11c3512af756c0051d0777d7--