caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] using a restricted subset of a polymorphic variant
@ 2015-09-10  9:07 Martin DeMello
  2015-09-10  9:12 ` Gabriel Scherer
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Martin DeMello @ 2015-09-10  9:07 UTC (permalink / raw)
  To: OCaml List

[-- Attachment #1: Type: text/plain, Size: 860 bytes --]

I'm not sure exactly why this doesn't work:

type dir = [`North | `South | `East | `West | `Up | `Down]

let index = function
  | `North -> 1
  | `South -> 2
  | `East -> 3
  | `West -> 4
  | `Up -> 5
  | `Down -> 6

class foo = object(self)
  val mutable heading = `Up

  method flip_heading =
    heading <- match heading with `Up -> `Down | `Down -> `Up

  method get_direction (x : dir) = index x

  method get_heading = self#get_direction heading
end

it fails with
File "test.ml", line 28, characters 42-49:
Error: This expression has type [ `Down | `Up ]
       but an expression was expected of type dir
       The first variant type does not allow tag(s)
       `East, `North, `South, `West

but why is that an error? I'd think that any function that accepts type dir
should accept type [`Down | `Up] as well. Also, how do I get this to work?

martin

[-- Attachment #2: Type: text/html, Size: 2402 bytes --]

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

* Re: [Caml-list] using a restricted subset of a polymorphic variant
  2015-09-10  9:07 [Caml-list] using a restricted subset of a polymorphic variant Martin DeMello
@ 2015-09-10  9:12 ` Gabriel Scherer
  2015-09-10  9:13 ` Edouard Evangelisti
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Gabriel Scherer @ 2015-09-10  9:12 UTC (permalink / raw)
  To: Martin DeMello; +Cc: OCaml List

This works if you remove the restrictive annotation (x : dir)
in the get_direction method, or replace it by the more flexible
(x : [< dir]). The type [ `Down | `Up ] of heading is distinct
from dir, but an instance of [< dir ].

On Thu, Sep 10, 2015 at 11:07 AM, Martin DeMello
<martindemello@gmail.com> wrote:
> I'm not sure exactly why this doesn't work:
>
> type dir = [`North | `South | `East | `West | `Up | `Down]
>
> let index = function
>   | `North -> 1
>   | `South -> 2
>   | `East -> 3
>   | `West -> 4
>   | `Up -> 5
>   | `Down -> 6
>
> class foo = object(self)
>   val mutable heading = `Up
>
>   method flip_heading =
>     heading <- match heading with `Up -> `Down | `Down -> `Up
>
>   method get_direction (x : dir) = index x
>
>   method get_heading = self#get_direction heading
> end
>
> it fails with
> File "test.ml", line 28, characters 42-49:
> Error: This expression has type [ `Down | `Up ]
>        but an expression was expected of type dir
>        The first variant type does not allow tag(s)
>        `East, `North, `South, `West
>
> but why is that an error? I'd think that any function that accepts type dir
> should accept type [`Down | `Up] as well. Also, how do I get this to work?
>
> martin
>

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

* Re: [Caml-list] using a restricted subset of a polymorphic variant
  2015-09-10  9:07 [Caml-list] using a restricted subset of a polymorphic variant Martin DeMello
  2015-09-10  9:12 ` Gabriel Scherer
@ 2015-09-10  9:13 ` Edouard Evangelisti
  2015-09-10 18:03   ` Martin Jambon
  2015-09-10  9:13 ` Christoph Höger
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Edouard Evangelisti @ 2015-09-10  9:13 UTC (permalink / raw)
  To: Martin DeMello, caml-list

[-- Attachment #1: Type: text/plain, Size: 1134 bytes --]

Dear Martin,

In your example, heading is not of type dir.
However, this would work :

val mutable heading : dir = `Up

Regards,
Edouard


2015-09-10 10:07 GMT+01:00 Martin DeMello <martindemello@gmail.com>:

> I'm not sure exactly why this doesn't work:
>
> type dir = [`North | `South | `East | `West | `Up | `Down]
>
> let index = function
>   | `North -> 1
>   | `South -> 2
>   | `East -> 3
>   | `West -> 4
>   | `Up -> 5
>   | `Down -> 6
>
> class foo = object(self)
>   val mutable heading = `Up
>
>   method flip_heading =
>     heading <- match heading with `Up -> `Down | `Down -> `Up
>
>   method get_direction (x : dir) = index x
>
>   method get_heading = self#get_direction heading
> end
>
> it fails with
> File "test.ml", line 28, characters 42-49:
> Error: This expression has type [ `Down | `Up ]
>        but an expression was expected of type dir
>        The first variant type does not allow tag(s)
>        `East, `North, `South, `West
>
> but why is that an error? I'd think that any function that accepts type
> dir should accept type [`Down | `Up] as well. Also, how do I get this to
> work?
>
> martin
>
>

[-- Attachment #2: Type: text/html, Size: 4047 bytes --]

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

* Re: [Caml-list] using a restricted subset of a polymorphic variant
  2015-09-10  9:07 [Caml-list] using a restricted subset of a polymorphic variant Martin DeMello
  2015-09-10  9:12 ` Gabriel Scherer
  2015-09-10  9:13 ` Edouard Evangelisti
@ 2015-09-10  9:13 ` Christoph Höger
  2015-09-10  9:19 ` Jacques Garrigue
  2015-09-10  9:22 ` Romain
  4 siblings, 0 replies; 8+ messages in thread
From: Christoph Höger @ 2015-09-10  9:13 UTC (permalink / raw)
  To: Martin DeMello; +Cc: caml users

You explicitly ask for an argument of type dir, but you want to ask for
an argument of any subtype of dir:

method get_direction (x : [< dir])

regards,

Christoph

Am 10.09.2015 um 11:07 schrieb Martin DeMello:
> I'm not sure exactly why this doesn't work:
> 
> type dir = [`North | `South | `East | `West | `Up | `Down]
> 
> let index = function
>   | `North -> 1
>   | `South -> 2
>   | `East -> 3
>   | `West -> 4
>   | `Up -> 5
>   | `Down -> 6
> 
> class foo = object(self)
>   val mutable heading = `Up
> 
>   method flip_heading =
>     heading <- match heading with `Up -> `Down | `Down -> `Up
> 
>   method get_direction (x : dir) = index x
> 
>   method get_heading = self#get_direction heading
> end
> 
> it fails with
> File "test.ml <http://test.ml>", line 28, characters 42-49:
> Error: This expression has type [ `Down | `Up ]
>        but an expression was expected of type dir
>        The first variant type does not allow tag(s)
>        `East, `North, `South, `West
> 
> but why is that an error? I'd think that any function that accepts type
> dir should accept type [`Down | `Up] as well. Also, how do I get this to
> work?
> 
> martin
> 


-- 
Christoph Höger

Technische Universität Berlin
Fakultät IV - Elektrotechnik und Informatik
Übersetzerbau und Programmiersprachen

Sekr. TEL12-2, Ernst-Reuter-Platz 7, 10587 Berlin

Tel.: +49 (30) 314-24890
E-Mail: christoph.hoeger@tu-berlin.de

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

* Re: [Caml-list] using a restricted subset of a polymorphic variant
  2015-09-10  9:07 [Caml-list] using a restricted subset of a polymorphic variant Martin DeMello
                   ` (2 preceding siblings ...)
  2015-09-10  9:13 ` Christoph Höger
@ 2015-09-10  9:19 ` Jacques Garrigue
  2015-09-10  9:22 ` Romain
  4 siblings, 0 replies; 8+ messages in thread
From: Jacques Garrigue @ 2015-09-10  9:19 UTC (permalink / raw)
  To: Martin DeMello; +Cc: OCaML List Mailing

On 2015/09/10 18:07, Martin DeMello wrote:
> 
> I'm not sure exactly why this doesn't work:
> 
> type dir = [`North | `South | `East | `West | `Up | `Down]
> 
> let index = function
>   | `North -> 1
>   | `South -> 2
>   | `East -> 3
>   | `West -> 4
>   | `Up -> 5
>   | `Down -> 6
> 
> class foo = object(self)
>   val mutable heading = `Up
> 
>   method flip_heading =
>     heading <- match heading with `Up -> `Down | `Down -> `Up
> 
>   method get_direction (x : dir) = index x
> 
>   method get_heading = self#get_direction heading
> end
> 
> it fails with
> File "test.ml", line 28, characters 42-49:
> Error: This expression has type [ `Down | `Up ]
>        but an expression was expected of type dir
>        The first variant type does not allow tag(s)
>        `East, `North, `South, `West
> 
> but why is that an error? I'd think that any function that accepts type dir should accept type [`Down | `Up] as well. Also, how do I get this to work?


The problem is that OCaml type inference uses unification rather than subtyping.
So [`Down | `Up] and dir are incompatible.

All the answers up to now seem to have assumed that get_direction should only accept [`Up | `Down].
This indeed solves the problem, but may not be what you intended.
If you still want get_direction to acception all directions, then you can either modify get_direction or get_heading
(but no need to change both):

   method get_direction : 'a. ([< dir] as 'a) -> int = index

with this polymorphic method annotation, you can now apply get_direction to heading

  method get_heading = self#get_direction (heading :> dir)

this one uses subtyping to convert heading to dir.

Jacques Garrigue



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

* Re: [Caml-list] using a restricted subset of a polymorphic variant
  2015-09-10  9:07 [Caml-list] using a restricted subset of a polymorphic variant Martin DeMello
                   ` (3 preceding siblings ...)
  2015-09-10  9:19 ` Jacques Garrigue
@ 2015-09-10  9:22 ` Romain
  4 siblings, 0 replies; 8+ messages in thread
From: Romain @ 2015-09-10  9:22 UTC (permalink / raw)
  To: caml-list

>    method get_heading = self#get_direction heading

This unifies heading (which has type [`Up | `Down]) with type dir, but 
types [`Up | `Down] and dir cannot be *unified*. However, [`Up | `Down] 
is a subtype of dir, so [`Up | `Down] can be *coerced* to type dir:

method get_heading = self#get_direction (heading :> dir)

Unification cannot guess coercions, so you have to annotate them by hand.

This may sound confusing, but I came up with an analogy some time ago 
which may help. (I'm probably not the only one who came up with it.)

A type can be seen as a set of values. For instance type [`Up | `Down] 
denotes the set of values `Up and `Down. This set is included in the set 
denoted by dir. [`Up | `Down] is a "subset" of dir, except we don't say 
"subset" but "subtype".

A polymorphic type can be seen as a set of types, i.e. a set of sets of 
values. Type [> `Up | `Down] denotes the set of all types which contain 
at least `Up and `Down. In particular, it contains [`Up | `Down]. So [> 
`Up | `Down] can be instantiated with [`Up | `Down].

Now you see that "is an instance of" is not the same as "is a subtype 
of": the first is inclusion between sets of sets of values, while the 
second is inclusion between sets of values.

Hope this helps,

-- 
Romain Bardou

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

* Re: [Caml-list] using a restricted subset of a polymorphic variant
  2015-09-10  9:13 ` Edouard Evangelisti
@ 2015-09-10 18:03   ` Martin Jambon
  2015-09-10 19:14     ` Martin DeMello
  0 siblings, 1 reply; 8+ messages in thread
From: Martin Jambon @ 2015-09-10 18:03 UTC (permalink / raw)
  To: OCaml Mailing List; +Cc: Edouard Evangelisti, Martin DeMello

I'd like to add that this a good systematic way to avoid confusing error 
messages when dealing with polymorphic variants (or objects). Just add 
type annotations on variables and function parameters which are 
polymorphic variants (or objects).

Here only one extra annotation would be needed, on the heading value:

   val mutable heading : dir = `Up
   method flip_heading = ...
   method get_direction (x : dir) = ...
   method get_heading = ...

The error message becomes closer to the actual error:

File "toto.ml", line 15, characters 15-61:
Warning 8: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
(`West|`South|`North|`East)

Martin

On 09/10/2015 02:13 AM, Edouard Evangelisti wrote:
> Dear Martin,
>
> In your example, heading is not of type dir.
> However, this would work :
>
> val mutable heading : dir = `Up
>
> Regards,
> Edouard
>
>
> 2015-09-10 10:07 GMT+01:00 Martin DeMello <martindemello@gmail.com
> <mailto:martindemello@gmail.com>>:
>
>     I'm not sure exactly why this doesn't work:
>
>     type dir = [`North | `South | `East | `West | `Up | `Down]
>
>     let index = function
>        | `North -> 1
>        | `South -> 2
>        | `East -> 3
>        | `West -> 4
>        | `Up -> 5
>        | `Down -> 6
>
>     class foo = object(self)
>        val mutable heading = `Up
>
>        method flip_heading =
>          heading <- match heading with `Up -> `Down | `Down -> `Up
>
>        method get_direction (x : dir) = index x
>
>        method get_heading = self#get_direction heading
>     end
>
>     it fails with
>     File "test.ml <http://test.ml>", line 28, characters 42-49:
>     Error: This expression has type [ `Down | `Up ]
>             but an expression was expected of type dir
>             The first variant type does not allow tag(s)
>             `East, `North, `South, `West
>
>     but why is that an error? I'd think that any function that accepts
>     type dir should accept type [`Down | `Up] as well. Also, how do I
>     get this to work?
>
>     martin
>
>

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

* Re: [Caml-list] using a restricted subset of a polymorphic variant
  2015-09-10 18:03   ` Martin Jambon
@ 2015-09-10 19:14     ` Martin DeMello
  0 siblings, 0 replies; 8+ messages in thread
From: Martin DeMello @ 2015-09-10 19:14 UTC (permalink / raw)
  To: Martin Jambon; +Cc: OCaml Mailing List, Edouard Evangelisti

[-- Attachment #1: Type: text/plain, Size: 2605 bytes --]

Thanks all! I was trying to express the fact that heading could only be `Up
or `Down but should act as a direction otherwise; Romain is right that I
was expecting the coercion to happen automatically (too much time in other
languages :)). Annotating

val mutable heading : [`Up | `Down] = `Up

and then coercing it when I pass it as a direction worked nicely.

martin

On Thu, Sep 10, 2015 at 11:03 AM, Martin Jambon <martin.jambon@ens-lyon.org>
wrote:

> I'd like to add that this a good systematic way to avoid confusing error
> messages when dealing with polymorphic variants (or objects). Just add type
> annotations on variables and function parameters which are polymorphic
> variants (or objects).
>
> Here only one extra annotation would be needed, on the heading value:
>
>   val mutable heading : dir = `Up
>   method flip_heading = ...
>   method get_direction (x : dir) = ...
>   method get_heading = ...
>
> The error message becomes closer to the actual error:
>
> File "toto.ml", line 15, characters 15-61:
> Warning 8: this pattern-matching is not exhaustive.
> Here is an example of a value that is not matched:
> (`West|`South|`North|`East)
>
> Martin
>
> On 09/10/2015 02:13 AM, Edouard Evangelisti wrote:
>
>> Dear Martin,
>>
>> In your example, heading is not of type dir.
>> However, this would work :
>>
>> val mutable heading : dir = `Up
>>
>> Regards,
>> Edouard
>>
>>
>> 2015-09-10 10:07 GMT+01:00 Martin DeMello <martindemello@gmail.com
>> <mailto:martindemello@gmail.com>>:
>>
>>     I'm not sure exactly why this doesn't work:
>>
>>     type dir = [`North | `South | `East | `West | `Up | `Down]
>>
>>     let index = function
>>        | `North -> 1
>>        | `South -> 2
>>        | `East -> 3
>>        | `West -> 4
>>        | `Up -> 5
>>        | `Down -> 6
>>
>>     class foo = object(self)
>>        val mutable heading = `Up
>>
>>        method flip_heading =
>>          heading <- match heading with `Up -> `Down | `Down -> `Up
>>
>>        method get_direction (x : dir) = index x
>>
>>        method get_heading = self#get_direction heading
>>     end
>>
>>     it fails with
>>     File "test.ml <http://test.ml>", line 28, characters 42-49:
>>     Error: This expression has type [ `Down | `Up ]
>>             but an expression was expected of type dir
>>             The first variant type does not allow tag(s)
>>             `East, `North, `South, `West
>>
>>     but why is that an error? I'd think that any function that accepts
>>     type dir should accept type [`Down | `Up] as well. Also, how do I
>>     get this to work?
>>
>>     martin
>>
>>
>>

[-- Attachment #2: Type: text/html, Size: 3864 bytes --]

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

end of thread, other threads:[~2015-09-10 19:14 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-10  9:07 [Caml-list] using a restricted subset of a polymorphic variant Martin DeMello
2015-09-10  9:12 ` Gabriel Scherer
2015-09-10  9:13 ` Edouard Evangelisti
2015-09-10 18:03   ` Martin Jambon
2015-09-10 19:14     ` Martin DeMello
2015-09-10  9:13 ` Christoph Höger
2015-09-10  9:19 ` Jacques Garrigue
2015-09-10  9:22 ` Romain

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