Lors de la création d'un client pour une API Web en C #, j'ai rencontré un problème concernant null
la valeur où cela représenterait deux choses différentes:
- rien , par exemple un
foo
peut ou peut ne pas avoir unbar
- inconnu : par défaut, la réponse de l'API ne comprend qu'un sous-ensemble de propriétés, vous devez indiquer les propriétés supplémentaires que vous souhaitez. Donc inconnu signifie que la propriété n'a pas été demandée à l'API.
Après quelques recherches, j'ai découvert le type Peut-être (ou Option), comment il est utilisé dans les langages fonctionnels et comment il "résout" les problèmes de déréférencement nul en forçant l'utilisateur à réfléchir à l'absence possible d'une valeur. Cependant, toutes les ressources que j'ai rencontrées parlaient de remplacer null par Maybe . J'ai trouvé quelques mentions de la logique à trois valeurs , mais je ne la comprends pas complètement et la plupart du temps, sa mention était dans le contexte de "c'est une mauvaise chose".
Je me demande maintenant s'il est logique d'avoir à la fois le concept de nul et peut - être , pour représenter respectivement inconnu et rien . Est-ce la logique à trois valeurs sur laquelle je lis ou a-t-elle un autre nom? Ou est-ce la manière prévue d'imbriquer un peut-être dans un peut-être?
null
. C'est une idée complètement brisée.M M x
etM x
devrait avoir la même sémantique.Maybe a
c'est la même chose , sémantiquement, c'est la même chose , et isomorphe à taper à partir de la réponse @Andej. Vous pouvez également définir votre propre instance de monade pour ce type et donc utiliser différents combinateurs de monade.Maybe Maybe a
UserInput a
M (M x)
etM x
devrait avoir la même sémantique". PrenezM = List
par exemple: les listes de listes ne sont pas la même chose que les listes. QuandM
est une monade, il y a une transformation (à savoir la multiplication de la monade) à partirM (M x)
deM x
laquelle explique la relation entre elles, mais elles n'ont pas "la même sémantique".Réponses:
La
null
valeur par défaut présente partout n'est qu'une idée vraiment cassée , alors oubliez cela.Vous devez toujours avoir exactement le concept qui décrit le mieux vos données réelles. Si vous avez besoin d'un type qui indique "inconnu", "rien" et "valeur", vous devriez l'avoir précisément. Mais si cela ne correspond pas à vos besoins réels, vous ne devriez pas le faire. C'est une bonne idée de voir ce que les autres utilisent et ce qu'ils ont proposé, mais vous n'avez pas à les suivre aveuglément.
Les personnes qui conçoivent des bibliothèques standard essaient de deviner les modèles d'utilisation courants, et ils le font généralement bien, mais si vous avez besoin d'une chose spécifique, vous devez la définir vous-même. Par exemple, dans Haskell, vous pouvez définir:
Il se peut même que vous utilisiez quelque chose de plus descriptif et plus facile à retenir:
Vous pouvez définir 10 de ces types à utiliser pour différents scénarios. L'inconvénient est que vous n'aurez pas de fonctions de bibliothèque préexistantes disponibles (comme celles de
Maybe
), mais cela se révèle généralement être un détail. Ce n'est pas si difficile d'ajouter vos propres fonctionnalités.la source
Pour autant que je sache, la valeur
null
en C # est une valeur possible pour certaines variables, selon son type (ai-je raison?). Par exemple, des instances d'une classe. Pour le reste des types (commeint
,bool
, etc.) , vous pouvez ajouter cette valeur d'exception en déclarant des variables avecint?
ou à labool?
place (ce qui est exactement ce que leMaybe
constructeur fait, comme je vais décrire suivante).Le
Maybe
constructeur de type de la programmation fonctionnelle ajoute cette nouvelle valeur d'exception pour un type de données donné. Donc, siInt
est le type d'entiers ouGame
est le type d'état d'un jeu, alorsMaybe Int
a tous les entiers plus une valeur nulle (parfois appelée rien ). Pareil pourMaybe Game
. Ici, aucun type n'est fourni avec lanull
valeur. Vous l'ajoutez quand vous en avez besoin.OMI, cette dernière approche est la meilleure pour n'importe quel langage de programmation.
la source
Maybe
et de supprimernull
complètement?isinstance
tests. Scala a également une correspondance de motifs «correcte», et C♯ a récemment gagné des motifs simples également.final
(pour une classe qui ne peut pas être héritée), il a égalementsealed
, pour un qui ne peut être étendue que dans la même unité de compilation . Cela signifie que le compilateur peut connaître statiquement toutes les sous-classes possibles (à condition qu'elles soient toutes elles-mêmessealed
oufinal
) et ainsi effectuer des vérifications d'exhaustivité pour les correspondances de modèles, ce qui n'est pas possible statiquement pour un langage avec chargement de code d'exécution et héritage illimité.int??
est illégal en C #.Si vous pouvez définir des unions de type, comme
X or Y
, et si vous avez un type nomméNull
qui représente uniquement lanull
valeur (et rien d'autre), alors pour n'importe quel typeT
, ilT or Null
n'est en fait pas si différent deMaybe T
. Le seul problème avecnull
est quand la langue traite un typeT
commeT or Null
implicitement, en faisantnull
une valeur valide pour chaque type (sauf les types primitifs dans les langues qui les ont). C'est ce qui se passe par exemple en Java où une fonction qui prend unString
accepte égalementnull
.Si vous traitez les types comme un ensemble de valeurs et
or
comme une union d'ensembles,(T or Null) or Null
représente alors l'ensemble de valeursT ∪ {null} ∪ {null}
, qui est le même queT or Null
. Il existe des compilateurs qui effectuent ce type d'analyses (SBCL). Comme indiqué dans les commentaires, vous ne pouvez pas facilement distinguer entreMaybe T
etMaybe Maybe T
lorsque vous affichez les types en tant que domaines (en revanche, cette vue est très utile pour les programmes typés dynamiquement). Mais vous pouvez également conserver les types en tant qu'expressions algébriques, où(T or Null) or Null
représentent plusieurs niveaux de Maybes.la source
Maybe (Maybe X)
ne soit pas la même chose queMaybe X
.Nothing
n'est pas la même chose queJust Nothing
. Un conflitMaybe (Maybe X)
avecMaybe X
rend impossible le traitementMaybe _
polymorphe.Vous devez découvrir ce que vous souhaitez exprimer, puis trouver un moyen de l'exprimer.
Tout d'abord, vous avez des valeurs dans votre domaine de problème (comme les nombres, les chaînes, les enregistrements clients, les booléens, etc.). Deuxièmement, vous avez des valeurs génériques supplémentaires en plus des valeurs de votre domaine problématique: par exemple, "rien" (l'absence connue d'une valeur), "inconnu" (aucune connaissance de la présence ou de l'absence d'une valeur), non mentionné était " quelque chose "(il y a certainement une valeur, mais nous ne savons pas laquelle). Vous pouvez peut-être penser à d'autres situations.
Si vous vouliez pouvoir représenter toutes les valeurs plus ces trois valeurs supplémentaires, vous créeriez une énumération avec les cas "rien", "inconnu", "quelque chose" et "valeur" et partir de là.
Dans certaines langues, certains cas sont plus simples. Par exemple, dans Swift, vous avez pour chaque type T le type "T optionnel" qui a pour valeur possible nil plus toutes les valeurs de T. Cela vous permet de gérer facilement de nombreuses situations et est parfait si vous n'avez "rien" et " valeur". Vous pouvez l'utiliser si vous avez "inconnu" et "valeur". Vous ne pouvez pas l' utiliser si vous devez gérer "rien", "inconnu" et "valeur". D'autres langues peuvent utiliser "null" ou "peut-être", mais ce n'est qu'un autre mot.
En JSON, vous avez des dictionnaires avec des paires clé / valeur. Ici, une clé peut simplement être manquante dans un dictionnaire, ou elle peut avoir une valeur nulle. Ainsi, en décrivant soigneusement la façon dont les choses sont stockées, vous pouvez représenter des valeurs génériques plus deux valeurs supplémentaires.
la source