Discussion:
types enregistrements et champs communs
(trop ancien pour répondre)
Biche de Cérynie
2010-02-18 14:33:26 UTC
Permalink
Bonjour,
Ce groupe semble mort, mais je tente quand même ma chance...

J'essaie de créer des types enregistrement ayant des champs de même
nom, et j'obtiens
des erreurs, par exemple

type a = {x:int; y:int};;
let t = {x=1;y=2};;
type b = {x:int; y:int};;
let u:b = {x=1;y=2};;
let v:a = {x=1;y=2};;

Ici les deux premiers "let" fonctionnent, mais le troisième
me fait une erreur
"Error: This expression has type b but is here used with type a"
soit si je comprends bien, ocaml comprends la valeur {x=1;y=2} comme
un "b",
grâce au typage automatique.

De même, t existe bien, mais si je demande t.x, il me fait cette
fois l'erreur
"Error: This expression has type a but is here used with type b"
c'est-à-dire que le champ x est associé au type b.

Je cherche un moyen de distinguer les champs en indiquant le type.
Il me semble que ça diot être faisable, mais je ne trouve pas...

Dans l'exemple précédant, ça ne sert encore à rien, mais
si je définit un type point2d et un type point3d, la
fonction
let getx p = p.x;;
va attendre une valeur du dernier déclaré des deux (ici un point3d)
Et je ne peux même pas faire
let getx p:point2d = p.x;;
qui génère aussi une erreur.

Quelqu'un aurait-il une idée ?
Biche de Cérynie
2010-02-18 14:47:18 UTC
Permalink
Post by Biche de Cérynie
Bonjour,
Ce groupe semble mort, mais je tente quand même ma chance...
J'essaie de créer des types enregistrement ayant des champs de même
nom, et j'obtiens
des erreurs, par exemple
type a = {x:int; y:int};;
let t = {x=1;y=2};;
type b = {x:int; y:int};;
let u:b = {x=1;y=2};;
let v:a = {x=1;y=2};;
Ici les deux premiers "let" fonctionnent, mais le troisième
me fait une erreur
"Error: This expression has type b but is here used with type a"
soit si je comprends bien, ocaml comprends la valeur {x=1;y=2} comme
un "b",
grâce au typage automatique.
De même, t existe bien, mais si je demande t.x, il me fait cette
fois l'erreur
"Error: This expression has type a but is here used with type b"
c'est-à-dire que le champ x est associé au type b.
Je cherche un moyen de distinguer les champs en indiquant le type.
Il me semble que ça diot être faisable, mais je ne trouve pas...
Dans l'exemple précédant, ça ne sert encore à rien, mais
si je définit un type point2d et un type point3d, la
fonction
let getx p = p.x;;
va attendre une valeur du dernier déclaré des deux (ici un point3d)
Et je ne peux même pas faire
let getx p:point2d = p.x;;
qui génère aussi une erreur.
Quelqu'un aurait-il une idée ?
Il y a une solution en écrivant :

module Pt2 = struct type coord = {x:int; y:int} end;;
module Pt3 = struct type coord = {x:int; y:int; z:int} end;;
{Pt2.x=1; Pt2.y=2};;
{Pt3.x=1; Pt3.y=2; Pt3.z=3};;
let get2x p = p.Pt2.x;;
let get3x p = p.Pt3.x;;

Ca me semble cependant un peu lourd. J'aimerais un moyen de faire la
même chose avec
des "types simples", pas des modules. Ou bien est-ce qu'un nom de
champ doit être
unique à un niveau de nom donné (par exemple, pas d'autre type
enregistrement ayant
un champ x dans Pt2 ou dans Pt3) ?
Biche de Cérynie
2010-02-18 14:56:28 UTC
Permalink
Post by Biche de Cérynie
Post by Biche de Cérynie
Bonjour,
Ce groupe semble mort, mais je tente quand même ma chance...
J'essaie de créer des types enregistrement ayant des champs de même
nom, et j'obtiens
des erreurs, par exemple
type a = {x:int; y:int};;
let t = {x=1;y=2};;
type b = {x:int; y:int};;
let u:b = {x=1;y=2};;
let v:a = {x=1;y=2};;
Ici les deux premiers "let" fonctionnent, mais le troisième
me fait une erreur
"Error: This expression has type b but is here used with type a"
soit si je comprends bien, ocaml comprends la valeur {x=1;y=2} comme
un "b",
grâce au typage automatique.
De même, t existe bien, mais si je demande t.x, il me fait cette
fois l'erreur
"Error: This expression has type a but is here used with type b"
c'est-à-dire que le champ x est associé au type b.
Je cherche un moyen de distinguer les champs en indiquant le type.
Il me semble que ça diot être faisable, mais je ne trouve pas...
Dans l'exemple précédant, ça ne sert encore à rien, mais
si je définit un type point2d et un type point3d, la
fonction
let getx p = p.x;;
va attendre une valeur du dernier déclaré des deux (ici un point3d)
Et je ne peux même pas faire
let getx p:point2d = p.x;;
qui génère aussi une erreur.
Quelqu'un aurait-il une idée ?
module Pt2 = struct type coord = {x:int; y:int} end;;
module Pt3 = struct type coord = {x:int; y:int; z:int} end;;
{Pt2.x=1; Pt2.y=2};;
{Pt3.x=1; Pt3.y=2; Pt3.z=3};;
let get2x p = p.Pt2.x;;
let get3x p = p.Pt3.x;;
Ca me semble cependant un peu lourd. J'aimerais un moyen de faire la
même chose avec
des "types simples", pas des modules. Ou bien est-ce qu'un nom de
champ doit être
unique à un niveau de nom donné (par exemple, pas d'autre type
enregistrement ayant
un champ x dans Pt2 ou dans Pt3) ?
Ok... alors la prochaine fois je cherche d'abord dans les archives :o)

Apparemment, le problème ne date pas d'hier, il est mentionné par X.
Leroy
en 1999 [1], et il subsiste en 2008 [2]. Je présume donc que c'est
toujours
comme ça, et que la solution pas très propre de mon second message est
la seule
pour l'instant.

[1] http://pauillac.inria.fr/caml/caml-list/1200.html
[2] http://caml.inria.fr/pub/ml-archives/caml-list/2008/03/cc53ea3f586696f948d4733b67a056ba.en.html
Joe Cool
2010-02-18 15:58:31 UTC
Permalink
Post by Biche de Cérynie
Ce groupe semble mort, mais je tente quand même ma chance...
Ce groupe est au contraire très vivant. Caml est un langage qui pose
peu de problèmes.
Post by Biche de Cérynie
J'essaie de créer des types enregistrement ayant des champs de même
nom, et j'obtiens
des erreurs, par exemple
type a = {x:int; y:int};;
let t = {x=1;y=2};;
type b = {x:int; y:int};;
let u:b = {x=1;y=2};;
let v:a = {x=1;y=2};;
Ici les deux premiers "let" fonctionnent, mais le troisième
me fait une erreur
C'est normal. Caml est basé sur l'inférence de type: le système
devine le type des données en fonction de la manière dont on les
utilise. Dans ce cas précis, rien ne distingue les données de type
a et de type b. Comme il y a une ambiguïté, et que le moteur
d'inférence ne gère pas le sous-typage, le système râle.

Il y a plusieurs moyens de contourner le problème:

1) on préfixe les champs des enregistrements pour les distinguer:

type a = { a_x : int ; a_y : int }
type b = { b_x : int ; b_y : int }
let t = { a_x = 1 ; a_y = 2 }
let u = { b_x = 1 ; b_y = 2 }

2) on sépare les espaces de noms avec des modules:

module A = struct type t = { x : int ; y : int} end
module B = struct type t = { x : int ; y : int} end
let t = { A.x = 1 ; A.y = 2 }
let u = { B.x = 1 ; B.y = 2 }

3) on préfixe les types par des constructeurs unaires:

type ab = { x : int ; y : int}
type a = A of ab
type b = B of ab
let t = A { x = 1 ; y = 2 }
let u = B { x = 1 ; y = 2 }

4) on utilise des objets immédiats:

type a = < x : int ; y : int >
type b = < x : int ; y : int >
let t : a = object method x = 1 method y = 2 end
let u : b = object method x = 1 method y = 2 end

dans ce cas on lève l'ambiguïté sur les types en typant
explicitement les valeurs t et u. C'est la seule méthode
vraiment générale car basée sur le sous-typage; elle permet
d'écrire ce genre de choses:

let t = object method x = 1 end
let u = object method x = 2 method y = 3 end
let get_2x a = 2 * a#x

# get_2x t;;
- : int = 2
# get_2x u;;
- : int = 4

C'est un peu verbeux, le bidule étant fait pour être manipulé via
des classes.
--
Joe Cool
Biche de Cérynie
2010-02-18 18:19:31 UTC
Permalink
Post by Joe Cool
Post by Biche de Cérynie
Ce groupe semble mort, mais je tente quand même ma chance...
Ce groupe est au contraire très vivant. Caml est un langage qui pose
peu de problèmes.
Ok, je croyais :-)

Merci pour les différentes pistes, ça va bien m'aider !

bdc
Biche de Cérynie
2010-02-18 18:34:03 UTC
Permalink
Post by Joe Cool
type ab = { x : int ; y : int}
type a = A of ab
type b = B of ab
let t = A { x = 1 ; y = 2 }
let u = B { x = 1 ; y = 2 }
Celle-ci ne marche pas non plus si on veut en faire quelque chose de
plus utile que simplement répéter le type
(sinon type b = a suffirait, voire même on n'en aurait jamais créé un
autre).

Par exemple si j'essaie de faire
type a = {x:int; y:int};;
type pt2 = Pt2 of a;;
type b = {x:int; y:int; z:int};;
type pt3 = Pt3 of b;;
on revient exactement au même problème qu'avant : Pt2 {x=1;y=2}
produit une erreur.

Il reste les autres options.
Biche de Cérynie
2010-02-18 18:43:08 UTC
Permalink
Post by Biche de Cérynie
Post by Joe Cool
type ab = { x : int ; y : int}
type a = A of ab
type b = B of ab
let t = A { x = 1 ; y = 2 }
let u = B { x = 1 ; y = 2 }
Celle-ci ne marche pas non plus si on veut en faire quelque chose de
plus utile que simplement répéter le type
(sinon type b = a suffirait, voire même on n'en aurait jamais créé un
autre).
Par exemple si j'essaie de faire
type a = {x:int; y:int};;
type pt2 = Pt2 of a;;
type b = {x:int; y:int; z:int};;
type pt3 = Pt3 of b;;
on revient exactement au même problème qu'avant : Pt2 {x=1;y=2}
produit une erreur.
Il reste les autres options.
On peut aussi contourner le problème :

type pt2 = { x:int; y:int };;
let mk2 x y = { x=x; y=y };;
let get2 p = p.x, p.y;;

type pt3 = { x:int; y:int; z:int };;
let mk3 x y z = { x=x; y=y; z=z };;
let get3 p = p.x, p.y, p.z;;

mk2 1 2;;
mk3 1 2 3;;

Mais ça ne marchera pas à tous les coups,
une fois qu'on a "oublié" le type, on ne peut plus créer de
fonction qui accède directement aux champs.
Ce qui est amusant, c'est qu'on peut encore
y accéder par les anciennes fonctions !

bcd
Joe Cool
2010-02-18 21:28:43 UTC
Permalink
Post by Biche de Cérynie
type pt2 = { x:int; y:int };;
let mk2 x y = { x=x; y=y };;
let get2 p = p.x, p.y;;
type pt3 = { x:int; y:int; z:int };;
let mk3 x y z = { x=x; y=y; z=z };;
let get3 p = p.x, p.y, p.z;;
mk2 1 2;;
mk3 1 2 3;;
Mais ça ne marchera pas à tous les coups,
une fois qu'on a "oublié" le type, on ne peut plus créer de
fonction qui accède directement aux champs.
Ce qui est amusant, c'est qu'on peut encore
y accéder par les anciennes fonctions !
C'est très amusant, en effet (ha ha); mais OCaml ne goûte pas
vraiment ce genre d'humour, comme on peut le constater avec
l'exemple suivant:

type a = A of int
let a1 x = A x

type a = A of int
let a2 x = A x

# (a1 0) = (a2 0);;
This expression has type a but is here used with type a

Il vaut mieux éviter de redéfinir des types, des champs ou des
valeurs avec des noms déjà utilisés.
--
Joe Cool
toucan
2010-02-22 17:00:27 UTC
Permalink
Post by Joe Cool
Post by Biche de Cérynie
type pt2 = { x:int; y:int };;
let mk2 x y = { x=x; y=y };;
let get2 p = p.x, p.y;;
type pt3 = { x:int; y:int; z:int };;
let mk3 x y z = { x=x; y=y; z=z };;
let get3 p = p.x, p.y, p.z;;
mk2 1 2;;
mk3 1 2 3;;
Mais ça ne marchera pas à tous les coups,
une fois qu'on a "oublié" le type, on ne peut plus créer de
fonction qui accède directement aux champs.
Ce qui est amusant, c'est qu'on peut encore
y accéder par les anciennes fonctions !
C'est très amusant, en effet (ha ha); mais OCaml ne goûte pas
vraiment ce genre d'humour, comme on peut le constater avec
type a = A of int
let a1 x = A x
type a = A of int
let a2 x = A x
# (a1 0) = (a2 0);;
This expression has type a but is here used with type a
Il vaut mieux éviter de redéfinir des types, des champs ou des
valeurs avec des noms déjà utilisés.
C'est normal, puisque ce ne sont pas les mêmes types... On peut au moins
attendre ça d'Ocaml !

Loading...