Nous avons tous vu entier, virgule flottante, chaîne et le type décimal occasionnel. Quels sont les types les plus étranges, uniques ou utiles que vous avez rencontrés, utiles ou non?
Nous avons tous vu entier, virgule flottante, chaîne et le type décimal occasionnel. Quels sont les types les plus étranges, uniques ou utiles que vous avez rencontrés, utiles ou non?
Réponses:
Je serai court:
Maybe a
à Haskell.
Avec cette construction simple, le langage résout le problème des plantages ou NullPointerException
, il contourne proprement le "One Million Mistake" de Tony Hoare :)
Franchement, une présence facultative vérifiée au moment de la compilation? C'est onirique ...
Option
nom. Pourquoi pas Optional
! C'est peut-être parce que je ne suis pas un locuteur natif, mais Option
ne me transmet pas le sens «facultatif».
Maybe
nom est mignon: "Qu'est-ce que tu as?" "Peut-être un Int". Cependant, ce qui est vraiment intéressant, c'est qu'il s'agit à la fois d'un foncteur et d'une monade, ce qui signifie, en clair, que vous obtenez gratuitement la propagation nulle. Vous n'avez jamais besoin de mettre des contrôles nuls à l'intérieur des fonctions ou au milieu de votre code; il vous suffit de le vérifier à la toute fin de votre code, voire pas du tout.
Maybe
monade pour Ruby: lostechies.com/derickbailey/2010/10/10/the-maybe-monad-in-ruby
Je l'aime toujours void *
. C'est probablement le symptôme de quelque chose de profondément imparfait en moi.
void *
et Pascal / Delphi ont Pointer
.
Lua a une table intégrée qui est la plus impressionnante. Il a une table de hachage et un vecteur intégrés, et avec l'utilisation de métatables peut être la base fondamentale de la programmation orientée objet dans un langage procédural.
Chaque index d'une table peut recevoir n'importe quelle structure de langage de base (nombre, booléen, chaîne, fonction -oui, les fonctions sont des types sur lua - et tables).
Je suis surpris que personne n'ait encore mentionné les monades ou les types de données algébriques.
Lisp a deux types intéressants: t
et nil
. Ce qui est intéressant chez eux, c'est que tout est un t
et rien n'est un nil
.
nil
un t
?
SNOBOL: modèle (essentiellement un arbre d'analyse LL (1), si je me souviens bien).
Fortran a des blocs communs; c'est l'un des types de données les moins courants dans les langues modernes, ou plutôt une manière inhabituelle de partager efficacement des données.
Fortran 95 a des types d'intervalles et des arithmétiques d'intervalles intégrés.
La liste ne serait pas complète sans types monadiques trouvés à Haskell. Pour les comprendre, il faut un peu d'effort.
Delphi a des ensembles ( voir aussi ), qui, je ne pense pas, sont implémentés de la même manière dans d'autres langages.
Cela rend le stockage d'attributs multi-variables dans les bases de données un jeu d'enfant: D
Je suppose que c'est vraiment étrange de la programmation sur une architecture classique, mais certainement l'un des types les plus difficiles pour moi de tourner la tête au début était le registre quantique , qui apparaît dans QCL .
PL / SQL vous permet de déclarer des variables de type my_table.some_column%type
... Je trouve ça sacrément utile.
Et C # vous permet de déclarer des objets comme nullables ou non, même si je ne suis pas sûr que cela compte comme un type.
cursor%rowtype
c'est encore plus drôle: c'est un type d'enregistrement formé dynamiquement qui reflète les colonnes que la requête du curseur renvoie.
J'avais un faible pour mon cœur les types de données d' Euphoria quand j'étais plus jeune
Il est structuré comme suit:
Object
-> Atom
-> Sequence
Séquence = une séquence d'objets
-- examples of atoms:
0
98.6
-1e6
-- examples of sequences:
{2, 3, 5, 7, 11, 13, 17, 19}
{1, 2, {3, 3, 3}, 4, {5, {6}}}
{{"jon", "smith"}, 52389, 97.25}
{} -- the 0-element sequence
Voir: Le manuel de référence
Remarque: "jon" est en fait un moyen rapide d'écrire la séquence de valeurs ASCII. Par exemple, "ABCDEFG"
c'est la même chose que{65, 66, 67, 68, 69, 70, 71}
Felix a des types de somme anonymes. Le type est écrit comme:
typedef il = int + long;
comme ce serait en théorie. Les valeurs sont moches:
case 0 of il (1)
case 1 of il (2L)
sauf peut-être pour une somme unitaire telle que 3 = 1 + 1 + 1
case 0 of 3
case 1 of 3
qui utilise malheureusement zéro origine pour la "compatibilité C". Des sommes anonymes sont nécessaires pour les types algébriques structurellement typés, par exemple:
(1 + T * li) as li
est une liste (liée individuellement) de T. Toutes les autres langues que je connais des sommes typiquement requises, où le type lui-même et les constructeurs doivent recevoir des noms.
Le raccourci 3 utilisé ci-dessus est mignon, ce qui suit est dans la bibliothèque:
typedef void = 0;
typedef unit = 1;
typedef bool = 2;
et cette notation:
T ^ 3
est un tableau de longueur statique 3 .. le 3 n'est pas un entier mais une somme de 3 unités. Quel dommage + n'est pas associatif :)
q / kdb + a des tables intégrées. Puisqu'il s'agit d'un langage de programmation et d'une base de données orientée colonne en un, il n'y a pas besoin de LINQ ou d'ORM.
Par exemple, peut créer une table comme celle-ci (l'affectation est distinguée par :
plutôt que =
comme dans la plupart des langues):
people:([]name:`Joe`Amy`Sarah; age:17 15 18; GPA:3.5 3.8 3.33)
Maintenant je peux regarder ma table:
q)show people
name age GPA
--------------
Joe 17 3.5
Amy 15 3.8
Sarah 18 3.33
Et je peux l'interroger:
q)select from people where GPA>3.4
name age GPA
------------
Joe 17 3.5
Amy 15 3.8
J'ai trouvé que les syndicats en C ++ étaient «originaux» quand j'ai entendu parler d'eux pour la première fois. Je n'ai toujours pas atteint un scénario où ils sont le choix évident à mettre en œuvre.
J'essaie toujours de comprendre ce qu'une fonction multi-paramètres devient en F # et dans d'autres langages fonctionnels. Fondamentalement, int f (Foo, Bar) devient func f (Foo)
C'est la fonction à deux paramètres qui prend un Foo, et une barre et retourne un int est vraiment une fonction à un paramètre qui prend un Foo et renvoie une fonction à un paramètre qui prend une barre et retourne un int. Mais vous pouvez l'appeler avec deux paramètres si vous le souhaitez. J'ai écrit un article à ce sujet ici
f(Foo, Bar)
est la même que la fonction f(Foo)
qui renvoie une autre fonction f'(Bar)
qui renvoie la valeur qui f(Foo, Bar)
retournerait. Autrement dit, si vous corrigez l'argument «Foo», mais pas «Bar», vous avez une fonction qui ne dépend pas de «Foo» mais dépend toujours de l'argument «Bar». Ceci est typique des langages fonctionnels; cela s'appelle «curry».
Ce sont des objets extrêmement puissants mais compacts.
Les langues qui les ont intégrées ont une grande capacité à manipuler du texte (ne permet pas d'entendre le mot analyser, elles ne sont pas si bonnes).
Une poignée de langues de la famille fonctionnelle ont une classe de types connue sous le nom d'Unity. La particularité des types Unity est qu'ils ne contiennent aucune information, ce sont des types à zéro bit. Un type d'unité (dans certaines variantes) est également sa seule valeur, ou (dans la plupart des autres) n'a qu'une seule valeur (qui n'est pas elle-même un type).
Ils sont cependant utiles, car ce sont des types distincts. Comme vous ne pouvez pas implicitement convertir d'un type d'unité à un autre, vous pouvez utiliser la vérification de type statique de manière très efficace et expressive.
L'unité est également la façon dont la plupart de ces langages décrivent les Enums, en permettant à un nouveau type d'être l'un d'un ensemble défini d'autres types, ou de décrire peut - être des types, des valeurs qui peuvent être soit une valeur d'un type typique (par exemple, un entier) ou ont une valeur qui représente aucune valeur.
Certains langages qui n'utilisent pas la richesse des types d'unités définis par l'utilisateur contiennent toujours l'unité, sous une forme ou une autre. Par exemple, Python a au moins trois types d'unité, NoneType
, NotImplementedType
et EllipsisType
. Il est intéressant de noter que les deux premiers signifient tous deux quelque chose comme "Aucune valeur", mais le troisième est utilisé dans des valeurs complexes (en particulier, des expressions de tranche) pour représenter des cas spéciaux intéressants.
D'autres exemples intéressants d'unité incluent NULL
en sql et undefined
en javascript, mais pas void
en C ou C ++. void
échoue. Même si elle décrit une valeur sans information, mais aucune valeur réelle ne peut être de type void
.
Le symbol
type de Ruby est un peu inhabituel. Il s'agit essentiellement d'une chaîne implémentant le modèle singleton. Ou quelque chose. Jusqu'à présent, j'ai trouvé que les meilleures utilisations des symboles étaient les états de suivi et les noms de fonction.
COBOL. Essentiellement, seuls deux types de données de base, des chaînes et des nombres, mais vous devez spécifier exactement comment ils sont disposés en mémoire, par exemple PIC S9(5)V99 COMP-3
.
S
= signé, 9(5)
= 5 chiffres, V
= virgule décimale implicite, 99
= 2 chiffres supplémentaires, COMP-3
= BCD + signe nybble.
Clipper avait des «blocs de code», qui étaient similaires aux méthodes anonymes. Ils peuvent être transmis et évalués au besoin, généralement sous forme de rappel. Vous les utiliseriez souvent pour des choses comme effectuer des calculs à la volée lors de la présentation de tableaux de données.
VHDL a des types physiques. Un littéral de ce type comprend à la fois une valeur et une unité. Vous pouvez également définir des sous-unités. Par exemple, un type physique prédéfini est time
:
type time is range <machine dependant> to <machine dependant>
units
fs;
ps = 1000 fs;
ns = 1000 ps;
us = 1000 ns;
Ms = 1000 us;
sec = 1000 ms;
min = 60 sec;
hr = 60 min;
end units;
Avec la surcharge de l'opérateur, vous pouvez définir des choses très intéressantes.
Clojure est intéressant car il a un méta-concept "d'abstractions" qui imprègne le langage. Exemples:
Dans une certaine mesure, les abstractions poussent à l'extrême le " principe de responsabilité unique ". C'est à vous de les composer pour obtenir les fonctionnalités que vous souhaitez, mais vous pouvez être extrêmement flexible sur la façon de les coller ensemble.
Par exemple, si vous voulez un système OOP basé sur une classe avec héritage, vous pouvez en créer une à partir de ces abstractions de base assez rapidement.
En pratique, les abstractions elles-mêmes sont conçues de manière à ce que plusieurs implémentations soient possibles, par exemple via des interfaces spécifiques comme clojure.lang.ISeq pour les séquences ou clojure.lang.IFn pour les fonctions d'ordre supérieur.
Il y a une vidéo intéressante sur ce sujet: L'art de l'abstraction
Googles Go a un type "Channel" qui est tout à fait unique.