caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Typing of recursive function with polymorphic variants
@ 2017-04-14 15:30 Vincent Jacques
  2017-04-14 18:11 ` Mikhail Mandrykin
  0 siblings, 1 reply; 4+ messages in thread
From: Vincent Jacques @ 2017-04-14 15:30 UTC (permalink / raw)
  To: caml-list

Hello,

utop # let rec f1 = function
  | `A x -> f1 x
  | `B -> `B;;
val f1 : ([< `A of 'a | `B ] as 'a) -> [> `B ] = <fun>

utop # let rec f2 = function
  | `A x -> f2 (f2 x)
  | `B -> `B;;
val f2 : ([< `A of 'a | `B > `B ] as 'a) -> 'a = <fun>

but I can *see* that f2 never returns an `A so I would give it the
same type as f1.

1) Would I be right or am I missing something?

2) Assuming I'm right, can you please give me hints about this
limitation of the typing algorithm?
I have a basic understanding of the W typing algorithm. Assuming that
a similar algorithm is used for polymorphic variants, I imagine that
when I call f2 (f2 x), f2's return type is "unified" with f2's
parameter type. Why is this needed?

3) The type of f2 is more generic than the type of f1. Could I use
type annotations to help the typing algorithm choose a more specific
type?

I tried to annotate f3 (f3 x) but I get different behaviors in utop
and in the compiler. I'm lost :)

utop # let rec f3 = function
  | `A x -> ((f3 (f3 x)):[`B])
  | `B -> `B;;
Error: This pattern matches values of type [? `A of [ `B ] ]
    but a pattern was expected which matches values of type [ `B ]
    The second variant type does not allow tag(s) `A

In a .ml file:

let rec f3 = function
  | `A x -> ((f3 (f3 x)):[`B])
  | `B -> `B

let () = f3

Error: This expression has type [ `B ] -> [ `B ]
    but an expression was expected of type unit

Thank you for your help,
-- 
Vincent Jacques
http://vincent-jacques.net

"S'il n'y a pas de solution, c'est qu'il n'y a pas de problème"
            Devise Shadock

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

* Re: [Caml-list] Typing of recursive function with polymorphic variants
  2017-04-14 15:30 [Caml-list] Typing of recursive function with polymorphic variants Vincent Jacques
@ 2017-04-14 18:11 ` Mikhail Mandrykin
  2017-04-14 18:47   ` Mikhail Mandrykin
  0 siblings, 1 reply; 4+ messages in thread
From: Mikhail Mandrykin @ 2017-04-14 18:11 UTC (permalink / raw)
  To: caml-list, Vincent Jacques

Hello,

On пятница, 14 апреля 2017 г. 17:30:33 MSK Vincent Jacques wrote:
> utop # let rec f2 = function
> 
>   | `A x -> f2 (f2 x)
>   | `B -> `B;;
> 
> val f2 : ([< `A of 'a | `B > `B ] as 'a) -> 'a = <fun>
> 3) The type of f2 is more generic than the type of f1. Could I use
> type annotations to help the typing algorithm choose a more specific
> type?
> 
> I tried to annotate f3 (f3 x) but I get different behaviors in utop
> and in the compiler. I'm lost :)
To give the function f2 the desired type ([< `A of 'a | `B ] as 'a) -> [> `B ] 
the type-checker needs to treat the type of this function (f2) as polymorphic 
inside the body of the function to avoid unifying the result type with the 
type of the first parameter. In OCaml this can be achieved by using an explicit 
polymorphic type annotation
(https://caml.inria.fr/pub/docs/manual-ocaml/extn.html#sec227): 

let rec f2 : 'a. ([<`A of 'a | `B ] as 'a) -> [`B]= function
  | `A x -> f2 (f2 x)
  | `B -> `B;;
val f2 : ([< `A of 'a | `B ] as 'a) -> [ `B ] = <fun>

> Assuming that
> a similar algorithm is used for polymorphic variants
Indeed, polymorphic variant types are treated by using constrained 
polymorphism integrated into usual HM type system, as described in the papers 
referenced here:
(http://ocaml.org/docs/papers.html#PolymorphicVariants).

> Why is this needed?
The unification is probably done because constrained type variables are treated 
as normal unification variables. AFAIK type inference for polymorphic recursion 
is undecidable (semidecidable) in general
(there are some references in this message
http://www.seas.upenn.edu/~sweirich/types/archive/1999-2003/msg00924.html)
and OCaml doesn't provide any incomplete support for some special cases, but 
allows to specify polymorphic types explicitly using those annotations.


--
Best,
Mikhail
> 
> utop # let rec f3 = function
> 
>   | `A x -> ((f3 (f3 x)):[`B])
>   | `B -> `B;;
> 
> Error: This pattern matches values of type [? `A of [ `B ] ]
>     but a pattern was expected which matches values of type [ `B ]
>     The second variant type does not allow tag(s) `A
> 
> In a .ml file:
> 
> let rec f3 = function
> 
>   | `A x -> ((f3 (f3 x)):[`B])
>   | `B -> `B
> 
> let () = f3
> 
> Error: This expression has type [ `B ] -> [ `B ]
>     but an expression was expected of type unit
> 
> Thank you for your help,


-- 
Mikhail Mandrykin
Linux Verification Center, ISPRAS
web: http://linuxtesting.org
e-mail: mandrykin@ispras.ru

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

* Re: [Caml-list] Typing of recursive function with polymorphic variants
  2017-04-14 18:11 ` Mikhail Mandrykin
@ 2017-04-14 18:47   ` Mikhail Mandrykin
  2017-04-15  8:23     ` Vincent Jacques
  0 siblings, 1 reply; 4+ messages in thread
From: Mikhail Mandrykin @ 2017-04-14 18:47 UTC (permalink / raw)
  To: Vincent Jacques; +Cc: caml-list

On пятница, 14 апреля 2017 г. 21:11:52 MSK Mikhail Mandrykin wrote:
> the desired type ([< `A of 'a | `B ] as 'a) -> [> `B]
> val f2 :                 ([< `A of 'a | `B ] as 'a) -> [ `B ] = <fun>
Actually, one more polymorphic variable:
let rec f2 : 'a 'b. ([<`A of 'a | `B ] as 'a) -> ([>`B] as 'b)= function
  | `A x -> f2 (f2 x)
  | `B -> `B;;
val f2 : ([< `A of 'a | `B ] as 'a) -> [> `B ] = <fun>

-- 
Mikhail

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

* Re: [Caml-list] Typing of recursive function with polymorphic variants
  2017-04-14 18:47   ` Mikhail Mandrykin
@ 2017-04-15  8:23     ` Vincent Jacques
  0 siblings, 0 replies; 4+ messages in thread
From: Vincent Jacques @ 2017-04-15  8:23 UTC (permalink / raw)
  To: Mikhail Mandrykin; +Cc: caml users

2017-04-14 20:47 GMT+02:00 Mikhail Mandrykin <mandrykin@ispras.ru>:
> let rec f2 : 'a 'b. ([<`A of 'a | `B ] as 'a) -> ([>`B] as 'b)= function
>   | `A x -> f2 (f2 x)
>   | `B -> `B;;
> val f2 : ([< `A of 'a | `B ] as 'a) -> [> `B ] = <fun>

Thank you Mikhail, this helps a lot.

I didn't know about polymorphic type annotations.

Thanks!
-- 
Vincent Jacques
http://vincent-jacques.net

"S'il n'y a pas de solution, c'est qu'il n'y a pas de problème"
            Devise Shadock

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

end of thread, other threads:[~2017-04-15  8:23 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-04-14 15:30 [Caml-list] Typing of recursive function with polymorphic variants Vincent Jacques
2017-04-14 18:11 ` Mikhail Mandrykin
2017-04-14 18:47   ` Mikhail Mandrykin
2017-04-15  8:23     ` Vincent Jacques

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