30

Moumou > bon je réponds d'abord à la nouvelle question. Non c'est 'a list qui est un sous-type de int list je crois. J'arrête pas de m'embrouiller avec ça à vrai dire c'est tordu mais... oui c'est ça. Si tu prends une valeur de type int list, tu ne peux en général pas la considérer comme une valeur de type 'a list. Par exemple [ 3 ] n'est pas de type 'a list. En revanche si tu prends une valeur de type 'a list, tu peux toujours la considérer comme une int list : c'est facile, il n'existe qu'une seule valeur de type 'a list et c'est [].

En fait il est faux que ocaml ne connaît pas le sous-typage, ce que veut dire BookeldOr c'est que ce sous-typage n'est jamais implicite. On m'a dit tout à l'heure qu'il n'était pas possible d'avoir à la fois le sous-typage implicite et l'inférence de types à la caml (je sais pas trop si c'est juste des questions de complexité d'algorithme ou si c'est plus profond que ça comme raisons). Mais tu as l'opérateur de coercition (je sais pas si on dit comme ça en français grin) qui force à considérer la valeur du sous-type comme une valeur du super-type. Exemple :
# ([] :> int list);;
- : int list = []
# ([1] :> 'a list);;
- : int list = [1]
# (`a :> [`a|`b]);;
- : [ `a | `b ] = `a
Tiens intéressant le deuxième résultat. Ah ben oui, en fait tu peux considérer [ 1 ] comme une 'a list à condition que 'a soit égal à int en fait, donc 'a list est bien d'un certain point de vue un sous-type de int list, mais sauf que c'est seulement pour une certaine valeur de 'a, c'est pas le type 'a list avec la variable libre...

bon je réponds à l'autre question dans un autre post ^^
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

31

Je crois que tu te trompes.

# let rec size = function
  | [] -> 0
  | h::t -> 1 + (size t);;
val size : 'a list -> int = <fun>

# [0; 1; 2; 3];;
- : int list = [0; 1; 2; 3]

# size [0; 1; 2; 3];;
- : int = 4


Pour moi celà veut dire que int list est un sous-type de 'a list vu que les fonctions qui prennent des 'a list en argument acceptent aussi des int list.

Enfin sur wikipedia:subtype, je lis :
Implementations of programming languages with subtyping fall into two general classes: inclusive implementations, in which the representation of any value of type A also represents the same value at type B if A<:B, and coercive implementations, in which a value of type A can be automatically converted into one of type B. The subtyping induced by subclassing in an object-oriented language is usually inclusive; subtyping relations that relate integers and floating-point numbers, which are represented differently, are usually coercive.

Donc l'implantation du sous-typage dans caml est inclusive. Mais pourquoi ont-ils choisi de faire ça plutôt que l'implantation coercitive qui me semble bien plus pratique ?
avatar
I'm on a boat motherfucker, don't you ever forget

32

./26 > ben je n'ai pas vraiment parlé que des opérations, non ; conceptuellement les types sont bien différents, on n'a pas 0 = 0. ; un flottant c'est une approximation, tu peux facilement prendre a et b non nuls tels que a +. b –. a = 0. , or le résultat n'est pas le *nombre* 0. Bon ceci dit je comprends ce que tu veux dire : on a une injection canonique de int vers float, puisque tout entier a une unique représentation sous forme de flottant, donc on peut faire comme si cette injection était une inclusion, ok.
Mais ça c'est d'un point de vue utilisateur ; après tu as aussi une raison technique : les représentations internes de 0 et de 0. sont complètement différentes, or en principe si t1 est un sous-type de t2 ça signifie qu'une instance de t1 peut être utilisée *telle quelle* là où une instance de t2 est attendue. D'ailleurs contrairement à ce que j'ai écrit ":>" n'est pas vraiment un opérateur, c'est juste une annotation (comme le ":" tout court) : ça donne des informations au vérificateur de types sans lesquelles il n'arriverait pas à typer correctement, mais ça ne touche pas à la valeur et ça n'a pas (enfin ça j'en suis moins sûr) d'incidence sur la compilation (à moins que je me plante complètement mais ça m'étonnerait, enfin ce que je raconte me semble vraisemblable en tous cas grin. Enfin il y a peut-être des optimisations qui utilisent le typage j'en sais rien, mais l'idée c'est que c'est comme si ça se passait comme je dis quoi cheeky). En fait tout ce que tu fais quand tu passes dans un super-type c'est que tu oublies un certain nombre d'informations sur ta valeur. Mais là en l'occurrence il ne suffit pas d'oublier que 0 est un entier pour qu'il se transforme spontanément en flottant, il faut réellement le convertir, donc ça marche pas.

Pour les caractères et les chaînes, je ne vois pas d'obstacle conceptuel aussi évident que pour les nombres, mais a priori on a le même problème qui est qu'une chaîne de un caractère est représentée différemment en interne de juste un caractère (je suppose qu'on pourrait choisir des représentations pour que ça marche mais je ne pense pas que ça ait beaucoup d'intérêt pratique hehe)

edit : cross
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

33

./31 > ah je vois ce que tu veux dire, mais le problème c'est que 'a list n'a pas une signification absolue puisque ça contient une variable... donc c'est normal qu'on se mélange ^^. Les variables sont globales à l'intérieur d'une expression de type donnée, je m'explique :
Pour moi une valeur est de type 'a list avec la variable libre si : pour toute valeur t de 'a, elle est de type t list.
Une fonction est de type 'a list -> unit (toujours avec la variable libre) si : pour toute valeur t de 'a, elle est de type t list -> unit.

Autrement dit, 'a list c'est l'intersection de tout les t list (donc c'est le singleton []).
Par contre, 'a list -> unit c'est le type des fonctions qui renvoient () et acceptent des arguments de type t list pour tout t, donc qui acceptent des arguments dans l'union de tous les t list.

Tiens à part ça j'ai fait un peu joujou cheeky
# let f = function `a -> `a | _ -> `b;;
val f : [> `a ] -> [> `a | `b ] = <fun>
# f `b;;
- : [> `a | `b ] = `b
# let b = (`b : [`b]);;
val b : [ `b ] = `b
# f b;;
This expression has type [ `b ] but is here used with type [> `a ]
The first variant type does not allow tag(s) `a
# (f :> [`b] -> 'a) b;;
- : [> `a | `b ] = `b
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

34

Sally
: c'est facile, il n'existe qu'une seule valeur de type 'a list et c'est [].

Pas seulement : une fonction polymorphe qui par exemple trierait une liste prend une 'a list et en renvoie une autre ^^ (bon, effectivement pour un appel particulier le type des arguments est bien défini et n'est pas 'a list si la liste n'est pas vide, mais du point de vue de l'intérieur de la fonction c'est bien un 'a list dans tous les cas)

En fait il est faux que ocaml ne connaît pas le sous-typage, ce que veut dire BookeldOr c'est que ce sous-typage n'est jamais implicite.

mumbleclassesmumble ? (un typage capable de les gérer doit bien pouvoir permettre d'écrire char = {i_am_a_char:yes;i_am_a_string:yes;...} et string = {i_am_a_string:yes;...}, ce qui àmha poutre pas mal, mais malheureusement ils ont eu la bonne idée de laisser la vieille lib standard et le système de types tel quel embarrassed)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

35

Moumou :
Pour moi celà veut dire que int list est un sous-type de 'a list vu que les fonctions qui prennent des 'a list en argument acceptent aussi des int list.

Non, justement, ça veut dire que int list est un super-type de 'a list (contravariance/covariance toussa) ^^
Mais pourquoi ont-ils choisi de faire ça plutôt que l'implantation coercitive qui me semble bien plus pratique ?

Pour des raisons de sûreté ? (on veut voir clairement là où il pourrait y avoir des erreurs d'arrondi)
Menfin bon ça serait nettement plus pratique si on pouvait avoir des "niveaux" de sûreté ("ici je calcule juste des statistiques vite fait, ne m'emmerde pas avec toutes ces conneries, un entier est un float toussa toussa")

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

36

Sally
: après tu as aussi une raison technique : les représentations internes de 0 et de 0. sont complètement différentes, or en principe si t1 est un sous-type de t2 ça signifie qu'une instance de t1 peut être utilisée *telle quelle* là où une instance de t2 est attendue.

Ce qui sux, je trouve sad
Pour les caractères et les chaînes, je ne vois pas d'obstacle conceptuel aussi évident que pour les nombres, mais a priori on a le même problème qui est qu'une chaîne de un caractère est représentée différemment en interne de juste un caractère (je suppose qu'on pourrait choisir des représentations pour que ça marche mais je ne pense pas que ça ait beaucoup d'intérêt pratique hehe)

Là par contre même avec l'architecture un peu merdique de Caml ça devrait pouvoir se faire, puisque Caml doit bien pouvoir discerner dynamiquement entre les deux ? (enfin effectivement ça demanderait peut-être de recoder proprement la lib standard avec des classes)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

37

Euh sinon pour l'histoire de l'inclusion et de la coercition je ne suis pas vraiment convaincu du fait que (x :> float) soit tellement plus pratique que float_of_int x, la différence c'est que dans la première expression x pourrait avoir potentiellement n'importe quel type qui soit un sous-type de float et pas nécessairement int, mais est-ce qu'on n'y perdrait pas en clarté ? dans tous les cas le compilateur serait obligé de connaître le type précis de x pour appeler la bonne fonction de conversion, donc on n'y gagnerait pas en expressivité (puisque si le type de x n'est pas connu par ailleurs on pourrait pas utiliser ce fait pour faire une fonction polymorphe, il faudrait au contraire écrire un truc du genre ((x : int) :> float) tritop)
edit : multicross
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

38

dans tous les cas le compilateur serait obligé de connaître le type précis de x pour appeler la bonne fonction de conversion, donc on n'y gagnerait pas en expressivité (puisque si le type de x n'est pas connu par ailleurs on pourrait pas utiliser ce fait pour faire une fonction polymorphe, il faudrait au contraire écrire un truc du genre ((x : int) :> float) tritop)

Ben si, grosso modo le système de type pour les classes de ocaml est à peu près potable, lui : (x :> float) serait tout simplement x#to_float... (cela dit en fait je ne vois pas dans quel cas on aurait envie de faire ça : si un char 'est' un string, alors il a les méthodes appropriées pour par exemple prendre le n-ième caractère, donc on a jamais besoin de le convertir en string, c'en est déjà un smile le problème dont tu parles est plutôt lié aux représentations : dans le cas où le type float est assez grand pour contenir tous les int, on peut changer de représentation au moment où on veut [potentiellement automatiquement] sans compromettre la sûreté, sinon effectivement le moment où le compilateur "choisit" de faire la conversion aura une influence sur le résultat, ce qui n'est pas glop du tout dans un système avec inférence de type [contrairement à un système où tous les types sont explicites et où ce genre de choses se "voit" et où c'est aussi explicite qu'un appel de fonction])

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

39

./34 > ben tu as effectivement les .. mais c'est du polymorphisme, c'est pareil qu'une variable de type : de même que le compilateur peut unifier int list et 'a list en choisissant 'a = int, il peut unifier <a : int; ..> et <a : int; b : int> en choisissant la bonne valeur de .., mais il ne peut pas faire mieux que ça tout seul. Si tu veux oublier une méthode tu es obligé de le faire explicitement avec :>

./38 > oui bien sûr ça marche avec des classes, mais je pensais que moumou voulait faire ça avec les représentations "normales" des int et des float
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

40

33) qui parle d'oublier ? un char 'est' un string dans tous les sens du termes...
37) ben le compilateur pourrait automatiquement générer des "templates" dans ces cas-là tongue (i.e. une fonction acceptant un (float tree) pourrait avoir une version (really_a_float tree) et une version (int_disguised_as_float tree))

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

41

33) euh je sais plus où on en est cheeky. Je voulais dire que <a : int; b : int> est un sous-type de <a : int> : il suffit d'oublier la méthode b pour convertir. Mais cette conversion n'est pas implicite en caml, si tu veux la faire il faut utiliser :>. Par contre <a : int; b : int> est automatiquement reconnu comme étant de type < a : int; ..>, ça ça marche ; mais c'est parce que .. est l'équivalent d'une variable de type, donc ce que tu fais n'est pas oublier b mais instancier cette variable.

37) oui mais c'est justement à ce propos que je disais que ça oblige à connaître le type précis de x à la compilation... ah ok tu veux dire que le choix de la version à utiliser pourrait être reporté ailleurs, oui c'est vrai
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

42

33) ok, mais concrètement, qu'est-ce que ça change ? de toute façon les types exacts style <a : int>, on s'en fiche, ils n'apparaissent qu'à la création des objets, mais si on voulait que string soit implémenté par le type a, on "remplacerait" tous les <a : int; ...> par "string" et voilà, non ? Ou alors il y a des cas où l'absence de ... est primordiale ?

37) valà©

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

43

Il me semblait que dans certains cas on était obligé d'utiliser le type exact mais je les retrouve pas... peut-être que c'était juste une limitation de l'implémentation du moment et qu'elle a été levée (?) ou alors j'ai rêvé ou alors c'est juste que je retrouve pas ^^
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

44

Pollux :
37) ben le compilateur pourrait automatiquement générer des "templates" dans ces cas-là tongue (i.e. une fonction acceptant un (float tree) pourrait avoir une version (really_a_float tree) et une version (int_disguised_as_float tree))


ok, donc comme je disais ce n'est pas de la compilation mais de la macro-génération, (avec le cas échéant de la propagation de code jusqu'à la compilation pour afficher des messages clairs,...)
Là par contre même avec l'architecture un peu merdique de Caml ça devrait pouvoir se faire, puisque Caml doit bien pouvoir discerner dynamiquement entre les deux ? (enfin effectivement ça demanderait peut-être de recoder proprement la lib standard avec des classes)


ocaml n'a aucun système de propagation de types, donc aucune vérification dynamique à l'exécution n'est possible (ce qui fait en partie son efficacité d'ailleurs!)

sinon, pour transformer une chaine en char et vice-versa, ça doit etre faisable avec des Obj.magic grin
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

45

let p x y = fun z -> z x y ;;

let q () = 
  let x1 = fun x -> p x x in 
  let x2 = fun z -> x1 (x1 z) in 
  let x3 = fun z -> x2 (x2 z) in 
  let x4 = fun z -> x3 (x3 z) in 
  let x5 = fun z -> x4 ( x4 z) in 
    x5 (fun z -> z);;


tiens, pour vous amuser, typez ça!
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

46

./44 > ben par exemple si caractère était un sous-type de chaîne comme propose Moumou, tu pourrais faire la vérification dynamiquement en regardant si la longueur de la chaîne est 1, il suffit de savoir que c'est une caractéristique qui suffit à définir le sous-type caractère.

Euh sinon c'est pas Obj.magic qui va faire que les caractères *seront* des chaînes de caractères, ça peut juste faire croire que c'en est jusqu'à ce que ça plante tripaf
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

47

BookeldOr
:
Pollux :
37) ben le compilateur pourrait automatiquement générer des "templates" dans ces cas-là tongue (i.e. une fonction acceptant un (float tree) pourrait avoir une version (really_a_float tree) et une version (int_disguised_as_float tree))

ok, donc comme je disais ce n'est pas de la compilation mais de la macro-génération, (avec le cas échéant de la propagation de code jusqu'à la compilation pour afficher des messages clairs,...)

Ben oui, c'est de la macro-génération si tu veux, mais je vois pas pkoi ça serait pas de la compilation trifus Et le typage c'est pas de la compilation ?
Là par contre même avec l'architecture un peu merdique de Caml ça devrait pouvoir se faire, puisque Caml doit bien pouvoir discerner dynamiquement entre les deux ? (enfin effectivement ça demanderait peut-être de recoder proprement la lib standard avec des classes)
ocaml n'a aucun système de propagation de types, donc aucune vérification dynamique à l'exécution n'est possible (ce qui fait en partie son efficacité d'ailleurs!)

Euh si, c'est possible, sinon comment crois-tu que les fonctions de comparaison ou d'affichage d'un objet générique font pour savoir quoi faire ? Par contre effectivement il n'y a aucune vérification dynamique dans les fonctions autres que ces fonctions "systèmes" parce que tout a été vérifié statiquement, mais ça n'a rien à voir avec ce que je disais ^^
sinon, pour transformer une chaine en char et vice-versa, ça doit etre faisable avec des Obj.magic grin

Oui mais non grin Obj.magic, ça contourne juste le typage (comme les casts du C), ça change pas la structure de mémoire derrière, et ça me paraît assez évident que les char et les string n'ont pas du tout la même structure interne en caml...

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

48

à priori,
le type chaine, c'est un pointeur (avec le bit de gc réservé) vers taille + zone mémoire
le tpe char est un int (enfin un mot) avec 1 bit pour le gc, des bits inutiles et 8bits pour le char
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

49

un char est un implémenté comme un int ? ah oui remarque pour les opérations de comparaison/copie/hachage ça pourrait coller ^^ (par contre pour l'affichage ça passe plus, mais je sais plus si l'affichage d'objet de type polymorphe est géré par ocamlopt ou si c'est juste le frontend interprété qui le permet what)

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

50

Euh si, c'est possible, sinon comment crois-tu que les fonctions de comparaison ou d'affichage d'un objet générique font pour savoir quoi faire ?

de quoi tu parles ?
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

51

le frontend n'est pas interprété hein tongue
il compile directement en bytecode à la suite de ce que tu as déja tapé avant dans l'interprète, affiche le typage donné par le compilateur de bytecode puis exécute et donne le résultat, et il n'y a pas plus d'infos de typage dans le bytecode que dans le code natif
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

52

       Objective Caml version 3.08.3
# let a = 3;;
val a : int = 3
# a;;
- : int = 3
# let c = 'a' ;;
val c : char = 'a'
# let i : int = (Obj.magic c);;
val i : int = 97
# let w : char = (Obj.magic 98);;
val w : char = 'b'
#

Ouais c'est bien ça donc.
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

53

./50: j'ai compris de quoi tu parlais tongue

pour la comparaison, si tu parles de =, <, etc.. ça n'est pas très compliqué, et effectivement c'est "dynamique" mais d'une façon pariculière,il ne vérifie pas le "type" dynamiquement:
il regarde si c'est un pointeur, si oui, il regarde la liste de données pointées et applique un < sur chaque champ, si ce n'est pas un pointeur, il regarde la zone mémoire (la taille est stockée) et compare le contenu à la bourrin (avec une particularité sioux pour les floats et ne pas prendre les NaN pour autre chose genre un pointeur, c'est assez space):

l'opé == est une comparaison directe de pointeurs.

genre (on pourrait trouver un bien plus sioux en générant une zone contenant la chaine "hello" avec des Obj.magic mais bon flemme tongue):
# type t = { i : int ; s : string } ;;
type t = { i : int; s : string; }
# type t2 =  { c : char ; s2 : string   } ;;
type t2 = { c : char; s2 : string; }
#    { i = 97  ; s = "hello" } =  (Obj.magic {c = 'a' ; s2 = "hello"  });;
- : bool = true


oh et le Obj.magic, j'utilise pas trop ça pour ce genre de merdes, plutot pour faire du downcasting comme en java:
Object o = new String("plop");
String s = (String) o;
(interdit par le typeur car non vérifiable statiquement, bien sur)

bon j'arrete là le monologue
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

54

Arg je viens de voir un truc encore pire que le fait que int ne soit pas compté comme sous-type de real.

{n : int} n'est même pas compté comme sur-type de {n : int; p : int} :/
avatar
I'm on a boat motherfucker, don't you ever forget

55

de toutes façons tu ne peux pas définir deux reccords avec un champ n sans passer par des modules différents...
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay

56

t'as fumé
# type a = {a : int};;
type a = { a : int; }
# type b = {a : int};;
type b = { a : int; }
# type c = {a : char};;
type c = { a : char; }
avatar
I'm on a boat motherfucker, don't you ever forget

57

L'exemple de base du sous-typage est que {x : int; y : int} est un sous type de {x : int}, mais caml ne sait même pas faire ça. Ca sux un peu, parce que c'est pourtant vachement bien le sous-typage sad Evidemment avec ocaml on a l'héritage, qui est sympa aussi, mais pas vraiment aussi bien (il faut explicitement déclarer l'héritage, alors que dans l'exemple plus haut, c'est implicite).

Ce serait pourtant fantastique un truc du genre :
# let f x = x.y;;
val f : ('a with 'a.y = 'b) -> 'b

love
avatar
I'm on a boat motherfucker, don't you ever forget

58

./56 > non il a raison... tu peux toujours déclarer plusieurs choses qui ont le même nom mais la nouvelle déclaration masque les anciennes, c'est exactement pareil que pour les identifiants. Tu n'as d'ailleurs même pas besoin de donner au type un nom différent pour que ça considère que tu as déclaré plusieurs types *différents* avec les mêmes noms de champs et que donc tu ne peux accéder qu'au dernier, regarde :
# type a = {a : int};;
type a = { a : int; }
# let x = {a = 0};;
val x : a = {a = 0}
# type a = {a : int};;
type a = { a : int; }
# x.a;;
This expression has type a but is here used with type a
trigic. Tu vois ? un record n'est pas du tout ce que tu crois, c'est quelque chose de beaucoup plus figé que ça... et donc pas question de sous-typage évidemment (le fait que tes champs a aient les mêmes noms ne fait pas qu'ils sont davantage compatibles pour ça). Bon les records ça a toujours été pourri hein... (enfin peut-être que si on maîtrise super bien le système de modules en fait c'est vachement utile dans certains cas, mais sinon c'est bel et bien pourri ^^) mais les classes ça fait exactement ce que tu veux (mais parfois il faut expliciter le sous-typage, comme je l'ai dit ; cf. fin du post)
# let f x = x#y;;
val f : < y : 'a; .. > -> 'a = <fun>

Euh sinon je crois que tu te trompes au sujet de l'héritage (enfin je comprends pas exactement ce que tu veux dire, mais sache que le mécanisme d'héritage est complètement indépendant du mécanisme de type... enfin évidemment quand tu définis une classe qui hérite d'une autre tu as des chances que les objets de cette classe se retrouvent par défaut avec un sous-type des objets de la classe parente, vu que tu ne peux pas privatiser une méthode, donc c'est quand même lié, mais je veux dire que le typeur s'en fout que tu aies déclaré la classe comme ci ou comme ça, d'ailleurs il ne sait même pas à quelle classe appartient l'objet, c'est d'ailleurs tout l'intérêt des classes...)

Pollux > j'ai retrouvé l'exemple : en fait le type des éléments d'une liste est forcément fermé, donc <m : int; ..> list ça n'existe pas, c'est obligatoirement <m : int> list, ce qui veut dire que pour mettre un élément de type <m : int; n : int> par exemple dans une telle liste tu es obligé d'utiliser ":>"
avatar
« Le bonheur, c'est une carte de bibliothèque ! » — The gostak distims the doshes.
Membrane fondatrice de la confrérie des artistes flous.
L'univers est-il un dodécaèdre de Poincaré ?
(``·\ powaaaaaaaaa ! #love#

59

BookeldOr :
       Objective Caml version 3.08.3
# let a = 3;;
val a : int = 3
# a;;
- : int = 3
# let c = 'a' ;;
val c : char = 'a'
# let i : int = (Obj.magic c);;
val i : int = 97
# let w : char = (Obj.magic 98);;
val w : char = 'b'
#

Ouais c'est bien ça donc.

OK, donc les char et les int ont la même représentation en interne (comme j'ai dit dans mon post c'est effectivement plausible), mais a priori pour les floats comme l'opérateur de comparaison n'est pas du tout le même il y a forcément un moyen de distinguer entre int et float dynamiquement...



Sally> beuh, l'algo d'inférence de type est pas assez malin pour savoir tout seul quoi faire dans ces cas-là ? cry c'est vrai que ça peut devenir une limitation pénible, si il faut passer son temps à caster manuellement vers le type voulu :/

« The biggest civil liberty of all is not to be killed by a terrorist. » (Geoff Hoon, ministre des transports anglais)

60

en fait, dans l'exmple de sally, le 2e a remplace le premier, le premier type n'existe plus...
avatar
fabetal_ > Hier, je me suis fait monter par un pote
redangel > et en chevals, ça donne quoi?
Nil> OMG I think I'm gay