Quelle est la différence entre “égal (=)” et “à l'identique (==)” en ocaml?
Dans OCaml
, nous avons deux sortes de equity comparisons
:
x = y
et x == y
,
Alors, quelle est exactement la différence entre eux?
Est que x = y
en ocaml comme x.equals(y)
en Java?
et x == y
comme x == y (comparing the address)
en Java?
OriginalL'auteur Jackson Tale | 2012-11-27
Vous devez vous connecter pour publier un commentaire.
Je ne sais pas exactement comment
x.equals(y)
fonctionne en Java. Si il le fait d'une "profonde" comparaison, l'analogie est assez proche. Une seule chose à faire attention est que l'égalité est un glissantes concept en OCaml (et fonctionnelle des langues en général). Le compilateur et le système d'exécution vont déplacer les valeurs, et peut-fusion et défusion pur (non-mutables) les valeurs à volonté. Vous devez utiliser uniquement==
si vous savez vraiment ce que vous faites. À un certain niveau, il exige une bonne connaissance de la mise en œuvre (qui est quelque chose à éviter, sauf si nécessaire).Les garanties qu'OCaml fait pour
==
sont faibles. Les valeurs mutables comparer physiquement l'égalité dans la façon que vous attendez (c'est à dire, si la mutation de l'un des deux va en fait muter les autres aussi). Mais pour les non-valeurs mutables, la seule garantie est que les valeurs que comparer physiquement l'égalité (==
) seront également considérées comme égales (=
). Notez que l'inverse est pas vrai, comme sepp2k points pour les valeurs flottantes.En substance, ce que le langage de spécification est vous dire pour les non-valeurs mutables, c'est que vous pouvez utiliser
==
comme une vérification rapide de décider si deux non-mutable valeurs sont égales (=
). Si ils comparent égales sur le plan physique, ils sont d'égale valeur-sage. Si ils ne comparez pas égales sur le plan physique, vous ne savez pas si ils sont de valeur égale-sage. Vous devez toujours utiliser=
de décider.equals
méthode et OCaml(=)
est que leequals
méthode fonctionne pour les types structurés tels que des cartes, des jeux, des tables de hachage. Le type polymorphe de OCaml(=)
fait des promesses que sa mise en œuvre ne peut remplir.D'accord, le OCaml
(=)
opérateur est plus compliqué qu'il n'y paraît, enclin à lever une exception, ou en boucle. Dans mon code j'ai eu de la chance avec elle, et ont rarement besoin d'écrire ma propre comparaison d'égalité.Je voudrais ajouter une forte mise en garde au sujet de la recommandation de l'utilisation de
==
pour un accès rapide, puisque le service d'exécution déjà que, dans la plupart des cas où il est sémantiquement correct. Je pense que le seul cas où il fait vraiment de sens de le faire manuellement est non à plat des structures de données pour laquelle vous arrive de savoir qu'aucun float, pas de fonction, et pas de balise abstraite peut jamais se produire à l'intérieur, mais le compilateur n'a pas.Vraiment excellent, merci!
OriginalL'auteur Jeffrey Scofield
Edit: cette réponse se plonge dans les détails de l'intérieur de OCaml, basé sur la
Obj
module. Que la connaissance n'est pas destiné à être utilisé sans soin (permettez-moi l'accent sur ce point, très important, une fois de plus: ne l'utilisez pas pour votre programme, mais uniquement si vous le souhaitez expérience avec OCaml runtime). Cette information est également disponible, quoique peut-être dans une forme plus compréhensible dans le O'Reilly livre sur OCaml, disponible en ligne (assez bon livre, bien qu'un peu daté maintenant).La
=
opérateur est la vérification de l'égalité structurelle, tandis que==
ne vérifie la présence physique de l'égalité.L'égalité de contrôle est basé sur la façon dont les valeurs sont attribuées et stockées dans la mémoire. Une valeur d'exécution en OCaml peut à peu près s'insérer dans 2 catégories différentes : soit boîte ou unboxed. L'ancien signifie que la valeur est accessible en mémoire par une indirection, et, plus tard, signifie que la valeur est directement accessible.
Depuis
int
(int31 sur les systèmes 32 bit, ou int63 sur les systèmes 64 bits) sont unboxed valeurs, les deux opérateurs se comportent de la même chose avec eux. Quelques autres types de valeurs, dont l'exécution des implémentations sont en faitint
, sera également de voir les deux opérateurs se comportant avec eux, comme unité()
, la liste vide[]
, des constantes dans algébrique de types et variantes polymorphes, etc.Une fois que vous commencez à jouer avec plus de valeurs complexes impliquant des structures, comme les listes, les tableaux, les tuples, les enregistrements (C struct équivalent), la différence entre ces deux opérateurs se dégage: les valeurs au sein de structures qui vont être mis en boîte, sauf s'ils peuvent être d'exécution représentée en tant que natif ints (1). Cette nécessité découle de la façon dont le système d'exécution doit gérer des valeurs, et de gérer la mémoire de manière efficace. Structuré valeurs sont attribués lors de la construite à partir d'autres valeurs, qui peuvent être eux-mêmes structurés de valeurs, auquel cas les références sont utilisées (car ils sont en boîte).
Parce que des allocations, il est très peu probable que les deux valeurs instanciées à différents points d'un programme pourrait être égales sur le plan physique, bien qu'ils seraient structurellement l'égalité. Chacun des champs, ou des éléments internes au sein de l'valeurs peuvent être identiques, même jusqu'à l'identité physique, mais si ces deux valeurs sont construites dynamiquement, alors ils seraient à l'aide de différents espaces de la mémoire, et donc être physiquement différents, mais structurellement l'égalité.
L'exécution essaie d'éviter d'inutiles allocations de bien: par exemple, si vous avez une fonction retournant toujours la même valeur (en d'autres termes, si la fonction est constante), soit simple ou structurée, cette fonction retournera toujours la même valeur (c'est à dire, les mêmes données en mémoire), ainsi que des tests de physique de l'égalité à la suite de deux appels de cette fonction sera couronnée de succès.
Un moyen d'observer si l'opérateur fait retour
true
est d'utiliser leObj.is_block
fonction de son exécution de la représentation (C'est-à-dire, le résultat deObj.repr
). Cette fonction indique simplement si son paramètre d'exécution de la représentation est en boîte.Un plus factice est d'utiliser la fonction suivante:
Cette fonction retournera un
int
qui est la valeur réelle de l'indicateur de la valeur liée àx
dans la mémoire, si cette valeur est boîte. Si vous l'essayez sur uneint
littéral, vous obtiendrez exactement la même valeur! C'est parce que les int sont unboxed (ie. la valeur est stockée directement dans la mémoire, non pas grâce à une référence).Maintenant que nous savons que boxed valeurs sont en fait des "référencé" valeurs", nous pouvons en déduire que ces valeurs peuvent être modifiées, même si le langage dit qu'ils sont immuables.
considérons par exemple le type de référence:
Nous pourrions définir une immuable ref comme ceci:
Et ensuite utiliser le
Obj.magic
fonction de forcer un type à l'autre, parce que structurellement, ces types de être réduit à la même exécution de la représentation.Par exemple:
Il y a quelques exceptions à cela:
si les valeurs sont des objets, alors même apparemment structurellement identique valeurs de retour
false
sur la comparaison structurelleici, nous voyons que
=
revient à l'équivalence physique.Si les valeurs sont des fonctions, vous ne pouvez pas les comparer structurellement, mais la comparaison fonctionne comme prévu.
paresseux valeurs peuvent ou peuvent ne pas être structurellement comparables, selon qu'ils ont été forcés ou non (respectivement).
module ou d'enregistrer les valeurs sont comparables si elles ne contiennent pas de valeur fonctionnelle.
En général, je pense qu'il est sûr de dire que les valeurs qui sont liées à des fonctions ou peuvent avoir des fonctions à l'intérieur ne sont pas comparables avec
=
, mais peut être comparé avec==
.Vous devez évidemment être très prudent avec tout ce: s'appuyer sur les détails de mise en œuvre de l'exécution est incorrect (Note: je blague utilisé le mot mal dans ma première version de cette réponse, mais modifiée par la peur d'être pris trop au sérieux). Comme vous l'avez justement souligné dans les commentaires, le comportement de l'javascript mise en œuvre est différente pour les flotteurs (structurellement équivalent en javascript, mais pas dans l'implémentation de référence, et ce sur le java?).
(1) Si je me souviens bien, les flotteurs sont aussi "unboxed" lorsqu'il est stocké dans tableaux pour éviter une double indirection, mais ils deviennent en boîte une fois extrait, vous ne devriez pas voir une différence de comportement avec boîte valeurs.
let phy x : int = Obj.magic (Obj.repr x);;
sera de retour uneint
”: C'est une erreur commune, mais il ne le fait pas. Elle renvoie une valeur de typeint
et dont le temps d'exécution de la représentation est inchangé, et donc ne pas avoir de ses plus bas de l'ensemble de bits. Si vous appliquez une fonction qui lit ce bit (commehash
ou, dans certaines circonstances,(=)
), alors la fonction se comporte comme il le fait pour les valeurs qui lui sont attribués. Si vous appliquez une arithmétiqueint
fonction qui fonctionne sans lire le bit de poids faible, vous obtiendrez unint
corrélée à l'adresse de la première valeur allouée...Si vous appliquez une arithmétique
int
fonction suppose le bit de poids faible de son argumentation est défini, vous pouvez obtenir un pointeur non valide, et le GC crash peu après. Un exemple du premier type de fonction arithmétique serait(lor) 0
, et de deuxième espèce typiquementsucc
.Et les deux commentaires ci-dessus ne sont que des exemples de pourquoi il est absolument mauvaise idée de mentionner le module
Obj
dans une réponse à une OCaml question posée par un débutant.bien sûr, c'est un abus de langage de dire qu'elle renvoie un int, puisque les deux
Obj.magic
etObj.repr
sont en fait la fonction identité. Dans le runtime monde, ces fonctions renvoient la valeur elle-même se répartit comme unint
, qui peut ou peut ne pas être un pointeur. Comme vous l'avez joliment point, j'aurais certainement clarifier le but de ma réponse, une erreur facilement corrigé. Merci pour vos commentaires!Il semble plus raisonnable avec l'avertissement en haut. Et, bonne liaison.
OriginalL'auteur didierc
Oui, c'est ça. Sauf que dans le cas d'OCaml vous pouvez utiliser
=
sur tout type de valeur, alors qu'en Java, vous ne pouvez pas utiliserequals
sur les types primitifs. Une autre différence est que les nombres à virgule flottante en OCaml sont des types référence, de sorte que vous ne devriez pas les comparer à l'aide de==
(pas que c'est généralement une bonne idée de comparer des nombres à virgule flottante directement pour l'égalité de toute façon).Donc en résumé, en gros, vous devez toujours utiliser
=
de comparer n'importe quel type de valeurs.So in summary, you basically should always be using = to compare any kind of values.
, alors pourquoi==
existant en ocaml? Quand utiliser==
exactement?De mon point de vue sur cette question dans ma réponse: vous pouvez l'utiliser en toute sécurité comme une vérification rapide pour l'égalité, de non-valeurs mutables, aussi longtemps que vous utilisez le plein
(=)
vérifier si la réponse est fausse. Il est également judicieux pour les valeurs mutables.Juste une petite question: pas tous les types de valeurs sont structurellement comparables, les valeurs fonctionnelles ne peuvent pas.
OriginalL'auteur sepp2k
selon http://rigaux.org/language-study/syntax-across-languages-per-language/OCaml.html,
==
vérifie peu profondes de l'égalité, et=
vérifie la profondeur de l'égalité==
renverra toujours false. Ne semble ni superficiel ni profond de moi.il est intéressant de noter que si vous essayez
1.0 == 1.0
dans try.ocamlpro.com, elle donne un vrai tout le tempsVoilà qui est intéressant! Il donne de faux dans 4.00.0 toplevel (juste testé). C'est vraiment impelementation dépendante je suppose que vous pourriez dire.
OriginalL'auteur Sam I am