caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] polymorphic variants in match statements
@ 2012-01-24  0:53 Milan Stanojević
  2012-01-24  1:21 ` Jacques Garrigue
  0 siblings, 1 reply; 6+ messages in thread
From: Milan Stanojević @ 2012-01-24  0:53 UTC (permalink / raw)
  To: caml-list

Hi, we're trying to understand the type inference with polymorphic
variants in match statements. This is a simplification of an actual
case that happened in practice.

1)
let f i a =
  match i, a with
  | true, `A -> `B
  | false, x -> x

fails with
File "foo.ml", line 4, characters 16-17:
Error: This expression has type [< `A ]
       but an expression was expected of type [> `B ]
       The first variant type does not allow tag(s) `B

2) changing false to _
let f i a =
  match i, a with
  | true, `A -> `B
  | _, x -> x

this succeeds with
val f : bool -> ([> `A | `B ] as 'a) -> 'a

3) changing x in (1) to _ , and using a on the right side
let f i a =
  match i, a with
  | true, `A -> `B
  | false, _ -> a

this fails in the same way as (1)

4) finally adding another case to match statement
let f i a =
  match i, a with
  | true, `A -> `B
  | false, x -> x
  | true, x -> x

this succeeds with the same type as (2)


So it seems there is some interaction between type inference and
exhaustivnest of the match statements.

Can someone shed some light on what is going on here?

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

* Re: [Caml-list] polymorphic variants in match statements
  2012-01-24  0:53 [Caml-list] polymorphic variants in match statements Milan Stanojević
@ 2012-01-24  1:21 ` Jacques Garrigue
  2012-01-24 17:42   ` Milan Stanojević
  0 siblings, 1 reply; 6+ messages in thread
From: Jacques Garrigue @ 2012-01-24  1:21 UTC (permalink / raw)
  To: Milan Stanojević; +Cc: caml-list

On 2012/01/24, at 9:53, Milan Stanojević wrote:

> Hi, we're trying to understand the type inference with polymorphic
> variants in match statements. This is a simplification of an actual
> case that happened in practice.
> 
> 1)
> let f i a =
>  match i, a with
>  | true, `A -> `B
>  | false, x -> x
> 
> fails with
> File "foo.ml", line 4, characters 16-17:
> Error: This expression has type [< `A ]
>       but an expression was expected of type [> `B ]
>       The first variant type does not allow tag(s) `B
> 
> 2) changing false to _
> let f i a =
>  match i, a with
>  | true, `A -> `B
>  | _, x -> x
> 
> this succeeds with
> val f : bool -> ([> `A | `B ] as 'a) -> 'a
> 
> 3) changing x in (1) to _ , and using a on the right side
> let f i a =
>  match i, a with
>  | true, `A -> `B
>  | false, _ -> a
> 
> this fails in the same way as (1)
> 
> 4) finally adding another case to match statement
> let f i a =
>  match i, a with
>  | true, `A -> `B
>  | false, x -> x
>  | true, x -> x
> 
> this succeeds with the same type as (2)
> 
> 
> So it seems there is some interaction between type inference and
> exhaustivnest of the match statements.
> 
> Can someone shed some light on what is going on here?

Indeed. The basic idea is to close variant types when leaving them
open would make the pattern matching non-exhaustive.
Here, if we assume that a has type [`A | `B], then the pattern-matching
becomes non-exhaustive, so the type inferred is just [`A]
(i.e. the list of all constructors appearing inside the patterns at this position).

Actually, the theory is a bit more complicated, and the full details are
in the following paper, but you should just expect the above behavior
in practice.

	Typing deep pattern-matching in presence of polymorphic variants.
	http://www.math.nagoya-u.ac.jp/~garrigue/papers/index.html

Note that there is also another way to make (1) type, without adding
new cases

  let f i a =
    match i, a with
    | true, `A -> `B
    | false, (`A as x) -> x;;
  val f : bool -> [< `A ] -> [> `A | `B ] = <fun>

Here we have removed the connection between a and the output,
allowing `A to be combine with `B without changing the type of a.

Hope this helps.

Jacques Garrigue



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

* Re: [Caml-list] polymorphic variants in match statements
  2012-01-24  1:21 ` Jacques Garrigue
@ 2012-01-24 17:42   ` Milan Stanojević
  2012-01-25  1:21     ` Jacques Garrigue
  2012-02-10 22:20     ` Milan Stanojević
  0 siblings, 2 replies; 6+ messages in thread
From: Milan Stanojević @ 2012-01-24 17:42 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: caml-list

Thanks a lot, Jacques!
This helped my understanding a lot.

I only wonder if maybe this (and other type checking issues) could be
documented in a better way. For example I couldn't find any links to
your papers on OCaml website


2012/1/23 Jacques Garrigue <garrigue@math.nagoya-u.ac.jp>:
> On 2012/01/24, at 9:53, Milan Stanojević wrote:
>
>> Hi, we're trying to understand the type inference with polymorphic
>> variants in match statements. This is a simplification of an actual
>> case that happened in practice.
>>
>> 1)
>> let f i a =
>>  match i, a with
>>  | true, `A -> `B
>>  | false, x -> x
>>
>> fails with
>> File "foo.ml", line 4, characters 16-17:
>> Error: This expression has type [< `A ]
>>       but an expression was expected of type [> `B ]
>>       The first variant type does not allow tag(s) `B
>>
>> 2) changing false to _
>> let f i a =
>>  match i, a with
>>  | true, `A -> `B
>>  | _, x -> x
>>
>> this succeeds with
>> val f : bool -> ([> `A | `B ] as 'a) -> 'a
>>
>> 3) changing x in (1) to _ , and using a on the right side
>> let f i a =
>>  match i, a with
>>  | true, `A -> `B
>>  | false, _ -> a
>>
>> this fails in the same way as (1)
>>
>> 4) finally adding another case to match statement
>> let f i a =
>>  match i, a with
>>  | true, `A -> `B
>>  | false, x -> x
>>  | true, x -> x
>>
>> this succeeds with the same type as (2)
>>
>>
>> So it seems there is some interaction between type inference and
>> exhaustivnest of the match statements.
>>
>> Can someone shed some light on what is going on here?
>
> Indeed. The basic idea is to close variant types when leaving them
> open would make the pattern matching non-exhaustive.
> Here, if we assume that a has type [`A | `B], then the pattern-matching
> becomes non-exhaustive, so the type inferred is just [`A]
> (i.e. the list of all constructors appearing inside the patterns at this position).
>
> Actually, the theory is a bit more complicated, and the full details are
> in the following paper, but you should just expect the above behavior
> in practice.
>
>        Typing deep pattern-matching in presence of polymorphic variants.
>        http://www.math.nagoya-u.ac.jp/~garrigue/papers/index.html
>
> Note that there is also another way to make (1) type, without adding
> new cases
>
>  let f i a =
>    match i, a with
>    | true, `A -> `B
>    | false, (`A as x) -> x;;
>  val f : bool -> [< `A ] -> [> `A | `B ] = <fun>
>
> Here we have removed the connection between a and the output,
> allowing `A to be combine with `B without changing the type of a.
>
> Hope this helps.
>
> Jacques Garrigue
>


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

* Re: [Caml-list] polymorphic variants in match statements
  2012-01-24 17:42   ` Milan Stanojević
@ 2012-01-25  1:21     ` Jacques Garrigue
  2012-02-10 22:20     ` Milan Stanojević
  1 sibling, 0 replies; 6+ messages in thread
From: Jacques Garrigue @ 2012-01-25  1:21 UTC (permalink / raw)
  To: Milan Stanojević; +Cc: caml-list

On 2012/01/25, at 2:42, Milan Stanojević wrote:

> Thanks a lot, Jacques!
> This helped my understanding a lot.
>
> I only wonder if maybe this (and other type checking issues) could be
> documented in a better way. For example I couldn't find any links to
> your papers on OCaml website

Actually they are there, but maybe not so visible.
There is a "papers" section in the "about" part of the site.
(Follow the link under the title)

http://caml.inria.fr/about/papers.en.html

Curiously there is no direct link from the "comprehensive"  
documentation index :-)

Jacques Garrigue

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

* Re: [Caml-list] polymorphic variants in match statements
  2012-01-24 17:42   ` Milan Stanojević
  2012-01-25  1:21     ` Jacques Garrigue
@ 2012-02-10 22:20     ` Milan Stanojević
  2012-02-11  1:14       ` Jacques Garrigue
  1 sibling, 1 reply; 6+ messages in thread
From: Milan Stanojević @ 2012-02-10 22:20 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: caml-list

A small follow-up question

Polymorphic variant types are not allowed to have non-regular
recursion, i.e. the following type definition gives an error

type 'a t = [ `A of 'a | `B of ('a * 'a) t ]

Error: In the definition of t, type ('a * 'a) t should be 'a t

I guess the reason why this is not allowed has something to do with
our previous discussion, but I'm struggling to connect the dots.

Can you please explain this restriction?




2012/1/24 Milan Stanojević <milanst@gmail.com>:
> Thanks a lot, Jacques!
> This helped my understanding a lot.
>
> I only wonder if maybe this (and other type checking issues) could be
> documented in a better way. For example I couldn't find any links to
> your papers on OCaml website
>
>
> 2012/1/23 Jacques Garrigue <garrigue@math.nagoya-u.ac.jp>:
>> On 2012/01/24, at 9:53, Milan Stanojević wrote:
>>
>>> Hi, we're trying to understand the type inference with polymorphic
>>> variants in match statements. This is a simplification of an actual
>>> case that happened in practice.
>>>
>>> 1)
>>> let f i a =
>>>  match i, a with
>>>  | true, `A -> `B
>>>  | false, x -> x
>>>
>>> fails with
>>> File "foo.ml", line 4, characters 16-17:
>>> Error: This expression has type [< `A ]
>>>       but an expression was expected of type [> `B ]
>>>       The first variant type does not allow tag(s) `B
>>>
>>> 2) changing false to _
>>> let f i a =
>>>  match i, a with
>>>  | true, `A -> `B
>>>  | _, x -> x
>>>
>>> this succeeds with
>>> val f : bool -> ([> `A | `B ] as 'a) -> 'a
>>>
>>> 3) changing x in (1) to _ , and using a on the right side
>>> let f i a =
>>>  match i, a with
>>>  | true, `A -> `B
>>>  | false, _ -> a
>>>
>>> this fails in the same way as (1)
>>>
>>> 4) finally adding another case to match statement
>>> let f i a =
>>>  match i, a with
>>>  | true, `A -> `B
>>>  | false, x -> x
>>>  | true, x -> x
>>>
>>> this succeeds with the same type as (2)
>>>
>>>
>>> So it seems there is some interaction between type inference and
>>> exhaustivnest of the match statements.
>>>
>>> Can someone shed some light on what is going on here?
>>
>> Indeed. The basic idea is to close variant types when leaving them
>> open would make the pattern matching non-exhaustive.
>> Here, if we assume that a has type [`A | `B], then the pattern-matching
>> becomes non-exhaustive, so the type inferred is just [`A]
>> (i.e. the list of all constructors appearing inside the patterns at this position).
>>
>> Actually, the theory is a bit more complicated, and the full details are
>> in the following paper, but you should just expect the above behavior
>> in practice.
>>
>>        Typing deep pattern-matching in presence of polymorphic variants.
>>        http://www.math.nagoya-u.ac.jp/~garrigue/papers/index.html
>>
>> Note that there is also another way to make (1) type, without adding
>> new cases
>>
>>  let f i a =
>>    match i, a with
>>    | true, `A -> `B
>>    | false, (`A as x) -> x;;
>>  val f : bool -> [< `A ] -> [> `A | `B ] = <fun>
>>
>> Here we have removed the connection between a and the output,
>> allowing `A to be combine with `B without changing the type of a.
>>
>> Hope this helps.
>>
>> Jacques Garrigue
>>


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

* Re: [Caml-list] polymorphic variants in match statements
  2012-02-10 22:20     ` Milan Stanojević
@ 2012-02-11  1:14       ` Jacques Garrigue
  0 siblings, 0 replies; 6+ messages in thread
From: Jacques Garrigue @ 2012-02-11  1:14 UTC (permalink / raw)
  To: Milan Stanojević; +Cc: caml-list

On 2012/02/11, at 7:20, Milan Stanojević wrote:

> A small follow-up question
> 
> Polymorphic variant types are not allowed to have non-regular
> recursion, i.e. the following type definition gives an error
> 
> type 'a t = [ `A of 'a | `B of ('a * 'a) t ]
> 
> Error: In the definition of t, type ('a * 'a) t should be 'a t
> 
> I guess the reason why this is not allowed has something to do with
> our previous discussion, but I'm struggling to connect the dots.
> 
> Can you please explain this restriction?

Actually, this is not directly related.
The problem here is with type inference of recursive types.
To do that, we need to do type inference on (possibly infinite) recursive trees.
This is easy for regular trees (which can be represent as a directed graph),
as the usual algorithm for first-order unification works.
So what ocaml does is building such a regular tree on the fly, by creating a
back edge to a previous ['a t] node when it meets another ['b t] node below it.

So for instance, with definition
  type 'a t = [ `A of 'a | `B of 'a t ]

the type [int t] would expand to ([`A of int | `B of 'r] as 'r)

However, for this to work, any occurrence of t inside its own definition
should have identical parameters. Hence the enforced restriction.

	Jacques Garrigue

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

end of thread, other threads:[~2012-02-11  1:14 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-24  0:53 [Caml-list] polymorphic variants in match statements Milan Stanojević
2012-01-24  1:21 ` Jacques Garrigue
2012-01-24 17:42   ` Milan Stanojević
2012-01-25  1:21     ` Jacques Garrigue
2012-02-10 22:20     ` Milan Stanojević
2012-02-11  1:14       ` 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).