caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Optional arguments "between" non-optional ones
@ 2010-09-23 13:20 Adrien
  2010-09-23 14:32 ` bluestorm
  0 siblings, 1 reply; 4+ messages in thread
From: Adrien @ 2010-09-23 13:20 UTC (permalink / raw)
  To: Caml Mailing List

Hi,

I was refactoring code today and hit a typing error that I couldn't
explain. I eventually tracked it down to the following:

  let f () ?a () =
    print_endline "bouh!"

  let h f =
    f () ()

  let () = h f;;  (* error is for "f" here *)

  Error: This expression has type unit -> ?a:'a -> unit -> unit
         but an expression was expected of type unit -> unit -> 'b


If I remove the first unit argument of f, then it works as expected.
There also seems to be variations around that.

Is there any explanation for that difference? And any chance of it
getting improved?

Thanks.


-- 

Adrien Nader


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

* Re: [Caml-list] Optional arguments "between" non-optional ones
  2010-09-23 13:20 [Caml-list] Optional arguments "between" non-optional ones Adrien
@ 2010-09-23 14:32 ` bluestorm
  2010-09-23 15:05   ` Adrien
  0 siblings, 1 reply; 4+ messages in thread
From: bluestorm @ 2010-09-23 14:32 UTC (permalink / raw)
  To: Adrien; +Cc: Caml Mailing List

(sorry for any double-posting)

The problem is that in your declaration of h, the inferred type for f
is of the form (unit -> unit -> ...), and you use it with the
different type (unit -> ?a:'a -> unit -> ...).

Changing ?a to be the first parameter of f change f's type to (?a:'a
-> unit -> unit -> ...). OCaml knows that it can implicitly coerce
functions when the optional parameters appear in the first position.

This is explained in the manual :
http://caml.inria.fr/pub/docs/manual-ocaml/manual006.html#htoc39

> However, in the specific case where the expected type
> is a non-labeled function type, and the argument is
> a function expecting optional parameters, the compiler
> will attempt to transform the argument to have it match
> the expected type, by passing None for all optional parameters.

A fix is to add an annotation when defining h :

let h (f : _ -> ?a:_ -> _) =
 f () ()

# let () = h f;;
bouh!
bouh!


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

* Re: [Caml-list] Optional arguments "between" non-optional ones
  2010-09-23 14:32 ` bluestorm
@ 2010-09-23 15:05   ` Adrien
  2010-09-24  1:32     ` Jacques Garrigue
  0 siblings, 1 reply; 4+ messages in thread
From: Adrien @ 2010-09-23 15:05 UTC (permalink / raw)
  To: bluestorm; +Cc: Caml Mailing List

On 23/09/2010, bluestorm <bluestorm.dylc@gmail.com> wrote:
> (sorry for any double-posting)
>
> The problem is that in your declaration of h, the inferred type for f
> is of the form (unit -> unit -> ...), and you use it with the
> different type (unit -> ?a:'a -> unit -> ...).
>
> Changing ?a to be the first parameter of f change f's type to (?a:'a
> -> unit -> unit -> ...). OCaml knows that it can implicitly coerce
> functions when the optional parameters appear in the first position.

I actually expected types (?a:'a -> unit -> unit -> ...) and (unit ->
?a:'a -> unit -> ...) to work alike. I'm wondering why the arguments
are "dropped" from the first case but not the second.

Also, that's what I've done: I've simply swapped two parameters in a
function and it's working well now.

> This is explained in the manual :
> http://caml.inria.fr/pub/docs/manual-ocaml/manual006.html#htoc39
>
>> However, in the specific case where the expected type
>> is a non-labeled function type, and the argument is
>> a function expecting optional parameters, the compiler
>> will attempt to transform the argument to have it match
>> the expected type, by passing None for all optional parameters.

Well spotted. I had gone a bit through the documentation but hadn't seen that.

> A fix is to add an annotation when defining h :
>
> let h (f : _ -> ?a:_ -> _) =
>  f () ()
>
> # let () = h f;;
> bouh!
> bouh!
>

I had tried to add an annotation too but (unit -> unit -> unit). Now,
thinking again about it and with your explanation, I understand better
why it had failed. I was trying to coerce f into a more restrictive
(or simply different?) type but the solution was keep the type of h's
argument broader.
Thanks.

--

Adrien Nader


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

* Re: [Caml-list] Optional arguments "between" non-optional ones
  2010-09-23 15:05   ` Adrien
@ 2010-09-24  1:32     ` Jacques Garrigue
  0 siblings, 0 replies; 4+ messages in thread
From: Jacques Garrigue @ 2010-09-24  1:32 UTC (permalink / raw)
  To: Adrien; +Cc: bluestorm, Caml Mailing List

On 2010/09/24, at 0:05, Adrien wrote:
> On 23/09/2010, bluestorm <bluestorm.dylc@gmail.com> wrote:
>> (sorry for any double-posting)
>> 
>> The problem is that in your declaration of h, the inferred type for f
>> is of the form (unit -> unit -> ...), and you use it with the
>> different type (unit -> ?a:'a -> unit -> ...).
>> 
>> Changing ?a to be the first parameter of f change f's type to (?a:'a
>> -> unit -> unit -> ...). OCaml knows that it can implicitly coerce
>> functions when the optional parameters appear in the first position.
> 
> I actually expected types (?a:'a -> unit -> unit -> ...) and (unit ->
> ?a:'a -> unit -> ...) to work alike. I'm wondering why the arguments
> are "dropped" from the first case but not the second.

The answer is that this way of coercing functions by applying optional
arguments when they are passed is a kind of hack. The formal semantics
defines optional argument discarding as happening only when a function
is applied. However, one often wants this discarding to occur when
the function is passed as argument, to avoid manual eta-expansion.
This is actually done through an eta-expansion (i.e., (fun x -> f x) gets
passed to the function instead of f, to be sure that side-effects happen at
the right time). Since only cases with a single eta-expansion are considered,
optional arguments should come first.

Of course we are very careful of not breaking the formal semantics
(where there is no eta-expansion, and discarding will only occur when
the function is applied). Whenever the eta-expansion approach might
introduce a discrepancy, you will get a type error.

Jacques Garrigue


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

end of thread, other threads:[~2010-09-24  1:32 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-23 13:20 [Caml-list] Optional arguments "between" non-optional ones Adrien
2010-09-23 14:32 ` bluestorm
2010-09-23 15:05   ` Adrien
2010-09-24  1:32     ` Jacques Garrigue

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