caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* How to handle try .... finally properly?
@ 2008-12-10 11:15 Conglun Yao
  2008-12-10 22:58 ` [Caml-list] " blue storm
  2008-12-11  0:09 ` Jacques GARRIGUE
  0 siblings, 2 replies; 4+ messages in thread
From: Conglun Yao @ 2008-12-10 11:15 UTC (permalink / raw)
  To: caml-list

Sorry, no replies in ocaml-beginner, post it again in caml-list.


Dear all,

I'm thinking about how to handle try .... finally in ocaml, and found
one of camlp4 implementations from
http://bluestorm.info/camlp4/dev/try/pa_tryfinally.ml.html

Example code adopted from Gabriel Scherer's pa_tryfinally

   Example Input :

     let transform f x =
       GlMat.push();
       try f x
       finally GlMat.pop()

   Output :

   let transform f x =
     (GlMat.push ();
     let after () = GlMat.pop ()
     and result = try `Result (f x) with | exn -> `Exn exn
     in (after ();
         match result with
         | `Result v -> v
         | `Exn e -> raise e))

At the first glance, it answered my question. However, it solved the
problem partially, only working on functions with one argument.

If we feed the * transform * a function with more than one argument,
(it is possible because of curring)

transform (fun x y -> .... some logic staff .... ) x y

will invoke the * after () * before the ((fun x y -> .....) x) y is
really executed.

Ideally, * transform * function is specified as allowing a function f
with only one parameter. But it seems impossible in OCaml,
as f : 'a -> 'b doesn't means f can and only accept one argument. ( 'b
could be 'c -> 'd ) If we could constraint 'b as a non-function type,
it can solve the problem.

Or someone knows a better solution to work around the problem.

Thanks.

Conglun


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Caml-list] How to handle try .... finally properly?
  2008-12-10 11:15 How to handle try .... finally properly? Conglun Yao
@ 2008-12-10 22:58 ` blue storm
  2008-12-11  0:09 ` Jacques GARRIGUE
  1 sibling, 0 replies; 4+ messages in thread
From: blue storm @ 2008-12-10 22:58 UTC (permalink / raw)
  To: Conglun Yao; +Cc: caml-list

> I'm thinking about how to handle try .... finally in ocaml, and found
> one of camlp4 implementations from
> http://bluestorm.info/camlp4/dev/try/pa_tryfinally.ml.html

As you probably noticed, the website is down right now. I'll see that
the files are reachable again as soon as possible (in the meantime, if
you want specific files, mail me and i'll send them). I should also
warn you that the files under the "dev/" prefix are "in development",
and not supposed to be stable or free of bugs.

> Example code adopted from Gabriel Scherer's pa_tryfinally
The example code actually comes from a mailing-list discussion :
http://caml.inria.fr/pub/ml-archives/caml-list/2007/01/31db0fd9b7e158f5679991560cb8f876.en.html

> At the first glance, it answered my question. However, it solved the
> problem partially, only working on functions with one argument.
>
> If we feed the * transform * a function with more than one argument,
> (it is possible because of curring)
>
> transform (fun x y -> .... some logic staff .... ) x y
>
> will invoke the * after () * before the ((fun x y -> .....) x) y is
> really executed.

In that particular case, using "transform f x" to send a function and
not a value would be plain wrong : the whole point of transform is "do
the dirty things" inside the push/pop of the OpenGL matrix. If you
push/pop when building your function, and then apply it later without
restoring the matrix at the application time, you'll get uncorrect
behavior, and this is not a try/finally-specific issue.

> Ideally, * transform * function is specified as allowing a function f
> with only one parameter. But it seems impossible in OCaml,
> as f : 'a -> 'b doesn't means f can and only accept one argument. ( 'b
> could be 'c -> 'd ) If we could constraint 'b as a non-function type,
> it can solve the problem.

This particular transform function is imperative in nature : the idea
is to do side effects at the right moment. You could probably enforce
the transformed function to return an unit type without that much loss
of generality :
  let transform (f : 'a -> unit) x = ...

That way, you can only transform ('a -> unit) functions, wich is a bit
limited (though you could use side-effects to send back values through
a reference for example) but should fit the intended use of the
function well.

In general, there is no solution to your problem. And I'm not even
sure there is a problem, as you could wish to protect the partial
evaluation of a function from raising exceptions : in some case, the
behaviour you find problematic will actually be the expected and right
thing to do.
If you want your function to be polymorphic, you have to accept it
could send anything back. If you want specialized "transform"
functions for curryfied two-arguments functions or more, you could
write ad-hoc functions for the 3, 4 or 5 parameters case. It sounds
ugly but is a practical solution, in the spirit of what the Haskellers
have done with their "zip, zip3, zip4, zip5" list functions (
http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-List.html#17
).


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Caml-list] How to handle try .... finally properly?
  2008-12-10 11:15 How to handle try .... finally properly? Conglun Yao
  2008-12-10 22:58 ` [Caml-list] " blue storm
@ 2008-12-11  0:09 ` Jacques GARRIGUE
  2008-12-11  0:52   ` Conglun Yao
  1 sibling, 1 reply; 4+ messages in thread
From: Jacques GARRIGUE @ 2008-12-11  0:09 UTC (permalink / raw)
  To: yaoconglun; +Cc: caml-list

From: "Conglun Yao" <yaoconglun@gmail.com>
>    Example Input :
> 
>      let transform f x =
>        GlMat.push();
>        try f x
>        finally GlMat.pop()
> 
> At the first glance, it answered my question. However, it solved the
> problem partially, only working on functions with one argument.
> 
> If we feed the * transform * a function with more than one argument,
> (it is possible because of curring)
> 
> transform (fun x y -> .... some logic staff .... ) x y
> 
> will invoke the * after () * before the ((fun x y -> .....) x) y is
> really executed.

A usual workaround in such situations is to first partially apply your
function to the (n-1) first arguments, as this should cause no
side-effects. Since I suppose you are really talking about

  transform f x y

you should rather write

  transform (f x) y

Note that this will not work properly if partial applications of f cause
side-effects (i.e. f is actually "fun x -> ...; fun y -> ...").
This is pretty rare, but I believe this is the case for printf for
instance.

Jacques Garrigue


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [Caml-list] How to handle try .... finally properly?
  2008-12-11  0:09 ` Jacques GARRIGUE
@ 2008-12-11  0:52   ` Conglun Yao
  0 siblings, 0 replies; 4+ messages in thread
From: Conglun Yao @ 2008-12-11  0:52 UTC (permalink / raw)
  To: Jacques GARRIGUE; +Cc: caml-list

> A usual workaround in such situations is to first partially apply your
> function to the (n-1) first arguments, as this should cause no
> side-effects. Since I suppose you are really talking about
>
>  transform f x y
>
> you should rather write
>
>  transform (f x) y
>

It indeed helps, forces to invoke  function f (with two parameters)
inside transform.

We know how to use transform properly, passing a function with only
one parameter or passing curried f with n-1 parameters.

But what if we were providing a library, users still might use it
incorrectly, thus it will cause a runtime error rather than compile
time error.

I know it's difficult and (even) impossible to do this kind of compile
time checking,
zip1, zip2, zip3, .... zip7, mentioned by blue storm, might be a
better solution.

Ask users to follow the convention,
use zip1 if f has one parameter
use zip2 if f has two parameters
....
use zip7 if f has seven parameters

OR

transform only accepts function with one parameter, multiple
parameters must be passed as a touple type like (a, b, c)


> Note that this will not work properly if partial applications of f cause
> side-effects (i.e. f is actually "fun x -> ...; fun y -> ...").
> This is pretty rare, but I believe this is the case for printf for
> instance.
>
> Jacques Garrigue
>


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2008-12-11  0:52 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-12-10 11:15 How to handle try .... finally properly? Conglun Yao
2008-12-10 22:58 ` [Caml-list] " blue storm
2008-12-11  0:09 ` Jacques GARRIGUE
2008-12-11  0:52   ` Conglun Yao

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).