Probablement dans un serpent Nishiki (Titre original: Peut-être en Python)

(Ce n'est pas un article traduit) Non.

C'est peut-être bon, non? Il est très facile de gérer l'état d'avoir une valeur et l'état de n'avoir aucune valeur. C'est l'apogée de la culture créée par Lirin.

Donc, j'ai pensé que je pourrais faire quelque chose de similaire avec Python et je l'ai implémenté.

Le corps principal est répertorié dans ici. Je pense que vous devriez certainement jouer et lancer Masakari.

spécification

Certains d'entre eux sont explicitement conscients de "les langues non sécurisées nulles ne sont plus des langues héritées", veuillez donc les lire ensemble. Je pense que c'est bien.

De base

This Maybe est implémenté comme des classes concrètes «Something» et «Nothing» qui héritent de la classe abstraite «Maybe». «Quelque chose» indique qu'il existe une valeur et «Rien» indique que la valeur est manquante.

La fonction just crée une instance de Something. «Nothing» est la (seule) instance de «Nothing».

from maybe import just, nothing

a = just(42)
b = nothing

print(a)
print(b)
Just 42
Nothing

Peut-être a la propriété has_value, Something renvoie True et Nothing renvoie False. En outre, «quelque chose» est lui-même vérité et «rien» est lui-même Falsey.

print(a.has_value)
print(b.has_value)

print('-----')

if a:
    print('a is Truthy')
else:
    print('a is Falsy')

if b:
    print('b is Truthy')
else:
    print('b is Falsy')
True
False
-----
a is Truthy
b is Falsy

Peut-être peut-il être considéré comme une boîte pour mettre des valeurs. Peut-être que lui-même peut être une valeur, alors Maybe peut être imbriqué. Peut-être a le concept de «profondeur». La profondeur de la valeur nue est 0. La profondeur de "Rien" est de 1. La profondeur de «quelque chose» est «profondeur du contenu + 1». La profondeur peut être obtenue en la passant à la fonction «dep».

from maybe import dep

a2 = just(a)
b2 = just(b)
print(a2)
print(b2)

print('-----')

print(dep(42))
print(dep(a))
print(dep(b))
print(dep(a2))
print(dep(b2))
Just Just 42
Just Nothing
-----
0
1
1
2
2

Peut-être peut comparer des valeurs égales. «Quelque chose» est supposé être égal s'ils sont «Quelque chose» et leur contenu est égal. S'il s'agit d'une structure imbriquée, elle sera creusée lors de la récurrence. «Rien» est supposé être égal s'ils sont «Rien».

print(a == 42)
print(a == just(42))
print(a == a2)
print(a == b)
print(b == nothing)
print(b == b2)
print(b2 == just(nothing))
False
True
False
False
True
False
True

Peut-être liant (cast avec vérification Null)

Pour utiliser Maybe [T] comme T,

1.Assurez-vous que Maybe a une valeur, 2. Vous devez convertir «Peut-être [T]» en «T».

Il est possible de l'utiliser comme suit en utilisant l'instruction if et l'opérateur de dépliage forcé décrits plus loin.

m = just(913)
if m.has_value:
    print(m.i + 555)
1488

Cependant, si ces deux processus sont séparés, les événements inattendus suivants peuvent se produire.

m = just(913)
if m.has_value:
    print(m + 555) #Oubliez le déballage, peut-être[int]Et int ne peut pas être ajouté
TypeError: unsupported operand type(s) for +: 'Something' and 'int'
m = nothing
print(m.i + 555) #Oubliez Null check, si m est Nothing, la mouche visqueuse
maybe.NullpoError: it GOT no value.

En fait, Maybe peut être itéré, Something génère la valeur du contenu une seule fois, et Nothing ne génère rien et déclenche une exceptionStopIteration (). En utilisant cela, vous pouvez utiliser l'instruction for pour effectuer une vérification Null et effectuer un cast en même temps, comme indiqué ci-dessous.

m = just(913)
for v in m:
    print(v + 555) #Ceci n'est exécuté que lorsque m est quelque chose
1468

J'appelle cela la «liaison peut-être» parce qu'elle ressemble à la liaison optionnelle Swift. La différence avec la liaison facultative est que l'observation (en utilisant le même nom de variable dans le bloc) n'est pas possible et que le branchement entre les valeurs manquantes est un peu compliqué.

Regardons-les dans l'ordre. Si vous faites quelque chose comme l'observation, le m changera de Maybe [int] à ʻint` dans la ligne de commentaire en raison de la portée variable de Python.

m = just(913)
print(m) #Ici peut-être[int]
for m in m:
    print(m + 555)
print(m) #Ici int
Just 913
1468
913

Pensez-vous que c'est plus pratique parce que vous avez déjà coché Null? Mais c'est un piège. Si la valeur de m est manquante, elle reste Maybe [int]. Vous n'êtes plus autorisé à traiter «m» dans le même contexte que «Peut-être» à partir de maintenant, vous devez passer votre temps à avoir peur de la possibilité que «m», qui ressemble à «int», ne soit «rien». Je ne sais pas à quoi sert peut-être. N'est-ce pas très différent de simplement utiliser "Aucun" (en fait, c'est plus gênant)?

La prochaine différence. Vous souhaiterez peut-être créer une branche du processus avec et sans valeur, plutôt que de simplement le faire lorsqu'il y a une valeur. Dans Swift Optional, vous pouvez écrire comme suit.

let m: Int? = nil
if let v = m {
    print(v + 555)
} else {
    print("Peut-être que tu me détestes?")
}

La correspondance entre «si» et «sinon» est belle et sans égal. Et ces deux blocs sont grammaticalement appariés.

Cependant, dans Peut-être, nous devons écrire comme ça.

m = nothing
for v in m:
    print(v + 555)
if not m.has_value:
    print("Peut-être que tu me détestes?")

La correspondance entre «pour» et «si» est probablement née et personne ne l'a jamais vue. En outre, ces deux blocs sont écrits l'un à côté de l'autre et ne constituent pas une paire grammaticale. De plus, «if not m.has_value» est assez long. À ce propos, «Rien» est à l'origine Fassy, donc «si ce n'est pas m» c'est bien, mais il y a un inconvénient que le sens est un peu difficile à lire.

Cela dit, il est beaucoup plus sûr et plus facile à écrire que le contrôle Null et le cast sont séparés. Fondamentalement, il est préférable d'interdire l'utilisation de .i et d'utiliser la liaison Maybe.

Opérateur de déballage forcé (de !, !!)

Considérons une fonction safe_int qui tente de convertir de str en ʻint et ne renvoie rien` si elle échoue.

def safe_int(s):
    try:
        return just(int(s))
    except ValueError:
        return nothing

En passant, disons que cette fonction contient une chaîne qui saute de la zone de texte "age" utilisée sur un certain site. Normalement, il est restreint de sorte que seuls les nombres puissent être saisis du côté HTML, et le prétraitement, etc. sera effectué avec JavaScript à l'étape précédente.

Dans de tels cas, il est pratiquement impossible pour cette fonction de renvoyer «rien». Cependant, Maybe [int] ne peut pas être utilisé comme ʻint, alors dois-je écrire une liaison Maybe pendant longtemps? Alors il vaut mieux utiliser None`.

C'est à ce moment que vous devez utiliser l'opérateur de dépliage forcé .i. Au fait, bien que ce soit appelé un opérateur, c'est en fait une propriété.

s = get_textbox('âge')
age = safe_int(s).i # .j'attribue un entier à l'âge
if age >= 20:
    ...

Cela semble pratique et sans tracas, mais si vous appelez .i pour rien, le bon vieux volera le NullpoError original. Encore une fois, l'opérateur de dépliage forcé est considéré comme une opération «non sûre» et ne doit être utilisé que là où il ne peut jamais être «rien» en logique.

Opérateur conditionnel nul (de ? .,? -> )

Supposons que vous ayez une «Peut-être [liste]» ici. Vous vouliez savoir combien il y a de «0» dans ce fichier. Je pense que Peut-être pourrait être «rien», mais la plupart du temps, si la liste elle-même n'existe pas, vous vous attendriez à «rien» (non, certaines personnes veulent «0»). Voir également «Null Healing Operator» suivant).

Pour être honnête, cela ressemble à ceci:

l = get_foobar_list('hogehoge')

for l0 in l:
    num_0 = just(l0.count(0))
if not l:
    num_0 = nothing

Je peux l'écrire avec certitude, mais pour être clair, c'est compliqué. Si l est liste, vous ne voulez pas écrire le processus qui nécessitenum_0 = l.count (0)sur 4 lignes.

Vous pouvez l'écrire de manière concise en utilisant l'opérateur conditionnel Null .q. (comme d'habitude, c'est vraiment une propriété).

l = get_foobar_list('hogehoge')
num_0 = l.q.count(0)

Vous pouvez également utiliser .q [] pour les indices.

l = get_foobar_list('hogehoge')
print(l.q[3])

#Peut être utilisé à la place de
# for l0 in l:
#     print(just(l0[3]))
# if not l:
#     print(nothing)

Pourquoi pouvons-nous faire cela? .Q renvoie un objet qui hérite de la classe abstraite SafeNavigationOperator. «SafeNavigationOperator» remplace «getattr» et «getitem». S'il a une valeur, "Something SNO" est renvoyé. Cela contient les informations de valeur, et __getattr__ et __getitem__ les enveloppent dans just et les renvoient. Si la valeur est manquante, NothingSNO est retourné, et __getattr__ et __getitem__ ne renvoient rien.

Vous vous demandez peut-être si vous avez une bonne idée ici. some_list.count est une méthode et un objet appelable. peut-être_list.q.count est retourné en encapsulant davantage la fonction dans Maybe. Est-ce un objet appelable de Maybe lui-même qu'il peut être traité comme l.q.count (0)?

En fait, c'est vrai. L'appel de Something appelle le contenu et encapsule le résultat dans juste et le renvoie. L'appel de "Nothing" renvoie simplement "rien". Cette spécification permet de faire les choses mentionnées ci-dessus. Cette spécification est à utiliser en même temps que «.q.». Personnellement, je pense que c'est magique de l'utiliser d'une autre manière, donc je pense qu'il vaut mieux s'abstenir de l'utiliser (cela conduit à la raison pour laquelle les quatre règles de Maybe, qui seront décrites plus loin, ne sont pas implémentées).

À propos, même parmi les langages qui implémentent «?.», Si la soi-disant «chaîne optionnelle» est adoptée, elle se terminera lorsque Null sera trouvé (pour ainsi dire, évaluation de court-circuit), mais «.q. Dans le cas de, le processus se poursuit avec «rien». Même si vous faites .q. pour rien, vous n'obtiendrez que rien, et le résultat de la propagation est toujours l'équivalent de Null, mais vous devez être conscient de cette différence. Vous devrez peut-être le conserver.

Au fait, vous ne pouvez pas faire quelque chose comme foo.q.bar = baz parce que vous n'avez pas remplacé __setattr__. C'est ma limitation technique et je ne pouvais tout simplement pas résoudre la boucle infinie qui se produit lorsque je remplace __setattr__. Aidez-moi, s'il vous plaît ... Je pense que foo.q [bar] = baz peut être fait, mais ce n'est pas encore implémenté car la symétrie est cassée.

Opérateur de fusion nul (de ?:, ??)

Dans le cas de Null, vouloir remplir avec la valeur par défaut est probablement la demande la plus courante lorsqu'il s'agit de Null.

Bien sûr, vous pouvez également écrire avec la liaison Maybe, mais ...

l = get_foobar_list('hogehoge')
num_0 = l.q.count(0) #Au fait, voici num_0 est peut-être[int]alors……

for v in num_0:
    num_0 = v
if not num_0:
    num_0 = 0

#Si tu sors d'ici, num_0 devient int.

L'opérateur de fusion Null [^ coalesce] >> est correctement préparé.

l = get_foobar_list('hogehoge')
num_0 = l.q.count(0) >> 0 # num_0 est un entier

Le comportement de l'opérateur de fusion Null semble simple à première vue (et est en fait simple), mais il nécessite un peu d'attention.

Si la valeur du côté gauche est manquante, l'histoire est facile et le côté droit est retourné tel quel.

En revanche, lorsque le côté gauche a une valeur, il se comporte de manière intéressante (au sens traductionnel d'Intéressant). Si le côté gauche est plus profond que le côté droit, le contenu du côté gauche et du côté droit sont réunis. Si le côté droit est plus profond que le côté gauche, enveloppez le côté gauche avec «juste», puis guérissez à nouveau. S'ils sont identiques, le côté gauche est renvoyé. Cependant, si le côté droit est une valeur nue (profondeur 0), enveloppez le côté droit dans juste et guérissez à nouveau et renvoyez le contenu.

L'opérateur «ou», qui se comporte de la même manière lorsqu'il est vu de l'extérieur, est un mouvement beaucoup plus compliqué que de le renvoyer tel quel si le côté gauche est Vérité. La raison de faire cela est qu'il renvoie toujours une valeur avec la même profondeur que le côté droit à la suite d'un appel récursif.

Dans le contexte de la «définition d'une valeur par défaut», vous vous attendez à ce qu'elle soit traitée de la même manière avec ou sans valeur. Peut-être peut être imbriqué, donc certaines opérations compliquées sont nécessaires. Cependant, c'est une histoire interne, et l'utilisateur peut simplement la traiter comme «renvoyant toujours une valeur avec la même structure».

Par exemple, lorsqu'il y a plusieurs Peut-être, quelle que soit leur structure, vous pouvez obtenir «Peut-être avec la même structure que le côté le plus à droite (valeur nue dans ce cas), où la valeur apparaît le plus tôt» comme suit. Je vais.

x = foo >> bar >> baz >> qux >> 999

D'autre part, veuillez noter que le côté droit est évalué car il ne s'agit pas d'une évaluation de court-circuit.

À propos, cet opérateur est implémenté en surchargeant l'opérateur de décalage de bit droit. Par conséquent, la priorité de calcul est également la même. Autrement dit, il est inférieur à l'opérateur d'addition et supérieur à l'opérateur de comparaison [^ operator-precedence]. Ceci est proche de la priorité de l'opérateur de fusion Null de C # [^ c-sharp], Swift [^ swift], Kotlin [^ kotlin], mais d'un autre côté, l'opérateur "None-aware" proposé dans PEP 505. C'est très différent de [^ pep-505], où ?? `a une priorité plus élevée que la plupart des opérateurs binaires. Soyez prudent lorsque le jour où la PEP 505 sera officiellement adoptée (je ne pense pas que cela viendra). De plus, «>> =» est automatiquement défini.

a = just(42)
b = nothing

print(a >> 0 + 12) # 42 ?? 0 +12 serait 54(Haz)

print('-----')

a >>= 999
b >>= 999

print(a)
print(b)
42
-----
42
999

En passant, j'ai choisi «>>» comme destination de surcharge.

  1. Certaines personnes écrivent de manière à ce que le «?» Manuscrit s'étende vers le bas à partir du «>» et forme un point (de forme similaire).
  2. «?» Et «>» sont côte à côte sur le clavier (similaire à l'opération de saisie)
  3. Lors de l'écriture de plusieurs éléments côte à côte, il est facile de comprendre visuellement que les valeurs sont vérifiées dans l'ordre à partir de la gauche (visualisation de la logique de traitement).
  4. Proche de la priorité de l'opérateur de fusion Null dans d'autres langues (moins déroutant)

Etc. ~~ Il semble que la raison tombe en panne, mais la raison est horriblement la modernisation, et vous pouvez voir que j'ai fait Maybe correctement. ~~

[^ coalesce]: Généralement, la traduction standard de Null Coalescing Operator est «Null coalescence operator», mais «coalescence» n'a pas la nuance de «remplir la partie manquante», donc cela signifie «fermer la plaie». «Guérison» est utilisé.

méthode map (from map)

L'opérateur conditionnel Null a en fait ses faiblesses. Il ne peut être utilisé qu'avec des objets Maybe. Vous ne pouvez pas non plus donner SafeNavigationOperator comme argument.

Cela signifie que vous ne pouvez pas faire cela.

l = just([1, 2, 3, ])

s = .q.sum(l) #Erreur de syntaxe
s = sum(l.q) #Exception à la pop

#Pourquoi tu ne fais pas ça
#Oah, oh, oh, oh, oh, ♥

Vous pouvez écrire avec la liaison Maybe, mais c'est toujours compliqué.

l = just([1, 2, 3, ])

for l0 in l:
    s = just(sum(l0))
if not l:
    s = nothing

Il existe une méthode map pour faire cela du côté objet Maybe. En utilisant la méthode map, vous pouvez écrire:

l = just([1, 2, 3, ])

s = l.map(sum)

La fonction passée à la méthode map renvoie le résultat encapsulé dans just. Bien sûr, si la valeur est manquante, «rien» ne sera renvoyé. Vous pouvez également utiliser des expressions lambda pour les fonctions, vous pouvez donc effectuer les opérations suivantes:

a = just(42)
print(a.map(lambda x: x / 2))
Just 21.0

Il n'y a pas grand chose à dire sur la méthode map (surtout si vous connaissez Monad).

Méthode bind (from flatMap)

Rappelez-vous la fonction safe_int que nous avons créée précédemment. Il prend str comme argument et renvoie Maybe [int]. Appliquons ceci à Maybe [str] en utilisant map.

s1 = just('12')
s2 = just('hogehoge')
s3 = nothing

print(s1.map(safe_int))
print(s2.map(safe_int))
print(s3.map(safe_int))
Just Just 12
Just Nothing
Nothing

safe_int renvoie Maybe, et la méthode map le réemballe avec just, donc il est imbriqué. Peut-être que la personne qui a écrit ce programme ne voulait pas de cette fin (le fait que "peut" être imbriqué le rend plus expressif. Par exemple, si le résultat de l'analyse JSON contient null, alorsjuste (rien), car si la clé n'existait pas en premier lieu, elle pourrait être exprimée par" rien ").

Jusqu'à présent, il était gardé secret, mais vous pouvez utiliser la fonction join pour écraser les nids d'une étape. C'est une conversion naturelle μ.

from maybe import join

print(join(s1.map(safe_int)))
print(join(s2.map(safe_int)))
print(join(s3.map(safe_int)))
Just 12
Nothing
Nothing

Et surtout, il est souhaitable de combiner «« map »et« join »». Si vous avez une méthode bind, vous pouvez l'utiliser.

print(s1.bind(safe_int))
print(s2.bind(safe_int))
print(s3.bind(safe_int))
Just 12
Nothing
Nothing

Pour ceux qui maîtrisent la ~~ transformation ~~ Haskell, vous pouvez facilement comprendre que la méthode map est l'opérateur <$> ʻopérateur et la méthode bind est l'opérateur >> = . Souvenez-vous de map pour les fonctions qui renvoient des valeurs nues et de bind` pour les fonctions qui renvoient Maybe.

Fonction do (à partir de la notation do)

Bien sûr, map et bind sont appelés à partir d'un seul objet Maybe, donc c'est un peu difficile à utiliser pour les fonctions qui prennent 2 arguments ou plus.

lhs = just(6)
rhs = just(9)

ans = lhs.bind(lambda x: rhs.map(lambda y: x * y))
print(ans)
Just 54

Au fait, l'intérieur est map car c'est une fonction qui renvoie une valeur nue avec x * y, et l'extérieur est bind parce que la valeur de retour de la méthode map est Maybe. Te souviens tu?

Vous pouvez facilement écrire ceci en utilisant la fonction do.

from maybe import just, nothing, do

lhs = just(6)
rhs = just(9)

ans = do(lhs, rhs)(lambda x, y: x * y)
print(ans)
Just 54

La fonction do extrait le contenu et exécute la fonction uniquement lorsque tous les arguments ont des valeurs. Renvoie «rien» s'il manque une valeur. Le nom «do» vient de Haskell, mais l'algorithme est extrêmement anti-monadique. Pardonne-moi.

Au fait, l'argument de la fonction do ne peut être pris que par Maybe. Si vous voulez utiliser des valeurs brutes comme arguments, enveloppez-les dans juste.

Autres choses

Peut-être en tant que conteneur

Peut-être est aussi un conteneur, et vous pouvez utiliser les opérateurs len et ʻin`.

La fonction «len» renvoie toujours «1» pour «Something» et «0» pour «Nothing».

a = just(42)
b = nothing
a2 = just(a)
b2 = just(b)

print(len(a))
print(len(b))
print(len(a2))
print(len(b2))
1
0
1
1

L'opérateur ʻin renvoie Truelorsque le contenu du côté droit est égal au côté gauche. Sinon, il renvoie «False».Nothing renvoie toujours False`.

print(42 in a)
print(42 in b)
print(42 in a2)
print(42 in b2)
True
False
False
False

Comme mentionné précédemment, Maybe peut être itératif. Ainsi, par exemple, vous pouvez le convertir en liste. @koher a dit: C'est exactement ce que le résultat est.

ʻOptional était une boîte qui pouvait être vide. D'un autre point de vue, vous pouvez considérer ʻOptional comme un ʻArray` qui peut contenir au plus un élément.

al = list(a)
bl = list(b)

print(al)
print(bl)
[42]
[]

Il est difficile de savoir s'il existe une opportunité d'utiliser les spécifications ici.

Connectez-vous avec le monde natif

Peut-être a une paire de fonctions et de méthodes, peut-être_from et to_native. C'est une paire de fonctions et de méthodes. Ceux-ci fonctionnent pour connecter les types natifs de Python avec Maybe.

peut-être_from prend une valeur native et retourne peut-être. La différence avec «juste» est que lorsque «Aucun» est donné, «rien» n'est renvoyé au lieu de «juste (Aucun)», et lorsque Maybe est donné, il est renvoyé tel quel. Cette fonction peut être utilisée pour utiliser collectivement les valeurs de retour des fonctions et méthodes existantes qui indiquent les valeurs de retour manquantes comme «None» dans le contexte commun de Maybe.

#Fonction existante qui renvoie None au lieu de price lorsqu'elle n'est pas dans le dictionnaire
def get_price(d, name, num, tax_rate=0.1):
    if name in d:
        return -(-d[name] * num * (1 + tax_rate)) // 1
    else:
        return None

# ...

from maybe import maybe_from
p = get_price(unit_prices, 'apple', 5) #int peut venir, aucun ne peut venir
p = maybe_from(p) #p est l'unité_aux prix'apple'Peut-être avec ou sans[int]

La méthode to_native, d'autre part, fait de Maybe une valeur native (bien que ce soit juste une native si le contenu est un objet fourni par une bibliothèque en premier lieu). Contrairement à .i, Nothing renvoie None (mais n'en abusez pas comme un opérateur de déroulement" sûr "), et même s'il est imbriqué, il creuse récursivement et est toujours nu. Renvoie la valeur de. map considère que tout est manquant lorsque l'argument est manquant, mais cela peut être utilisé pour l'argument d'une fonction qui s'attend à donner" Aucun "pour ne signifier aucune valeur. Vous pouvez également le spécifier en tant que méthode de sérialisation JSON en utilisant le fait qu'elle renvoie une valeur native (bien qu'elle soit abrégée en native).

import json

from maybe import Maybe

def json_serial(obj):
    if isinstance(obj, Maybe):
        return obj.to_native()
    raise TypeError ("Type {type(obj)} not serializable".format(type(obj)))

item = {
    'a': just(42),
    'b': nothing
}

jsonstr = json.dumps(item, default=json_serial)
print(jsonstr)
{"a": 42, "b": null}

Différences par rapport à PyMaybe et réponses à "N'est-ce pas juste un problème?"

Quand vous dites Peut-être en Python, il existe une bibliothèque existante appelée «PyMaybe». Il semble que ce soit un endroit célèbre mentionné dans la PEP 505.

La grande caractéristique ici est que vous pouvez gérer Maybe comme s'il s'agissait d'une valeur nue. Plus précisément, le code suivant dans README.rst sera utile. Pensez à «peut-être» comme «peut-être» ici, et «ou_else» comme «>> ʻopérateur ici.

>>> maybe('VALUE').lower()
'value'

>>> maybe(None).invalid().method().or_else('unknwon')
'unknwon'

Nous appelons une méthode pour les valeurs brutes pour les valeurs qui sont enveloppées dans Maybe. Vous pouvez également voir que l'appel de méthode pour Null est ignoré et que Null est propagé. Vous n'êtes pas obligé de le retirer ou de faire «.q» comme mon Maybe. Il semble que des méthodes Dunder telles que quatre règles soient également implémentées.

Pourquoi n'est-ce pas plus pratique? Je pense que beaucoup de gens pensent qu'il n'y aura pas d'erreurs supplémentaires.

Cependant, il y a une raison pour laquelle j'ai implémenté Maybe avec une telle spécification. Il s'agit simplement de «soulever une erreur».

Si vous ne reconnaissez pas correctement la différence entre Maybe [T] et T, vous obtiendrez immédiatement une erreur, ce qui vous aidera à remarquer la différence. Si vous le confondez, vous obtiendrez une erreur immédiatement, et si vous le convertissez en chaîne, il aura un préfixe Just supplémentaire. C'est pour s'assurer que "si vous ne l'écrivez pas correctement, cela ne fonctionnera pas". Si vous faites une erreur, vous la remarquerez immédiatement (voir: Si vous êtes sérieux, n'ayez pas peur de "l'année optionnelle (2018)"). C'est aussi la raison pour laquelle je ne veux pas que vous appeliez directement Maybe (car cela cache la différence, même si je veux vraiment effacer la conversion de chaîne ...).

La sécurité nulle est généralement comprise comme un mécanisme qui ne cause pas de glu, et il ne fait aucun doute que le but ultime est là (et soudain j'ai commencé à parler de sécurité nulle, mais mon Les indices de type de Maybe sont inutiles, il est donc pratiquement impossible de les utiliser pour la sécurité Null). Cependant, ce qui est vraiment nécessaire pour la sécurité Null est "une distinction entre Nullable et Non-null". Pourquoi Java n'a-t-il pas échoué? C'était que vous pouviez attribuer null à n'importe quel type de référence, et inversement, la valeur de tout type de référence pouvait être null. Le fait que «T» puisse être Null signifie que vous ne pouvez pas l'utiliser comme «T» même si vous avez écrit «T». Devrait être. S'y rendre et briser davantage la barrière entre Nullable et Non-null - laisser les choses qui ne sont pas «T» être traitées comme «T» - est plutôt dangereux.

Objective-C a une mauvaise spécification selon laquelle les appels de méthode à «nil» sont ignorés sans erreur.

(Omis)

Cependant, en échange de cette commodité, Objective-C comporte également un risque terrifiant. J'ai oublié de cocher «nil» là où j'aurais dû cocher «nil», mais parfois cela fonctionne. Et un jour, lorsque certaines conditions se chevauchent ou qu'une petite correction est apportée, le bogue devient apparent.

Le traitement par Objective-C des «nil» semble sûr à première vue, ne faisant que retarder la découverte des problèmes et les rendre plus difficiles à résoudre. Je considère que la méthode Objective-C est la pire en ce qu'elle est sujette à des bogues potentiels. Il était une fois, lors du portage d'un programme écrit en Objective-C vers Java, il a fallu attendre une exception "NullPointerException" en Java que je me suis rendu compte que la gestion "nil" du côté Objective-C était inappropriée. était.

Bien sûr, cela ne signifie pas que vous devez être moins productif pour la sécurité Null. La vérification Null pour les variables Nullable était nécessaire «même dans l'ancien langage» [^ null-check], et cela a peut-être plutôt implémenté diverses façons de le simplifier. Si vous voulez le frapper sans vérifier Null, il existe même une opération Unsafe pour cela. Cette zone est [une histoire racontée il y a quelques années](https://qiita.com/koher/items/e4835bd429b88809ab33#null-%E5%AE%89%E5%85%A8%E3%81%AF%E7 % 94% 9F% E7% 94% A3% E6% 80% A7% E3% 82% 82% E9% AB% 98% E3% 82% 81% E3% 82% 8B).

Cependant, je pense que ceux qui aiment utiliser Python sont conscients de cette robustesse et valorisent quand même "écrivez ce que vous voulez écrire honnêtement". Donc, je ne peux pas dire que l'idée de PyMaybe est fausse ~~ Je peux dire que je suis le "Peut-être que [T] erroriste" qui se rebelle contre le monde ~~. Cependant, n'hésitez pas à dire que vous jouez à moitié, ou que vous avez écrit ce que vous voulez écrire.

[^ null-check]: Ceci est une histoire irréaliste pour un peut-être personnalisé, mais si [n'utilisez que «rien» et pas le «None» intégré](https://twitter.com/ kmizu / status / 782360813340286977) Si vous pouvez (enveloppez-le dans peut-être_from dès que cela peut se produire), vous n'avez pas besoin de faire une vérification Null pour les valeurs brutes. En fait, c'est le plus grand avantage des langages Null-safe, et les langages Null-safe qui ont un tel mécanisme intégré dans leurs spécifications de langage n'ont besoin que d'un "contrôle Null nécessaire". La perception générale selon laquelle «les langages sûrs nuls forcent les vérifications nulles» est correcte, mais le contraire est vrai. Référence: [Anti-pattern] Syndrome qui peut être totalement nul (nul)

Recommended Posts

Probablement dans un serpent Nishiki (Titre original: Peut-être en Python)
Prendre une capture d'écran en Python
Créer une fonction en Python
Créer un dictionnaire en Python
Créer un bookmarklet en Python
Dessinez un cœur en Python
Ecrire une dichotomie en Python
[python] Gérer les fonctions dans une liste
Appuyez sur une commande en Python (Windows)
Créer un conteneur DI avec Python
Dessinez une matrice de diagramme de dispersion avec python
ABC166 en Python A ~ C problème
Ecrire des algorithmes A * (A-star) en Python
Créer un fichier binaire en Python
Résoudre ABC036 A ~ C avec Python
Ecrire un graphique à secteurs en Python
Ecrire le plugin vim en Python
Écrire une recherche de priorité en profondeur en Python
Implémentation d'un algorithme simple en Python 2
Implémentation du tri original en Python
Résoudre ABC037 A ~ C avec Python
Exécutez un algorithme simple en Python
Dessinez un diagramme CNN en Python
Créer une chaîne aléatoire en Python
Lors de l'écriture d'un programme en Python
Générer une collection de première classe en Python
Livre en spirale en Python! Python avec un livre en spirale! (Chapitre 14 ~)
Résoudre ABC175 A, B, C avec Python
Utiliser l'impression dans l'expression lambda Python2
Un client HTTP simple implémenté en Python
Faites une visite Euler non récursive en Python
J'ai fait un programme de gestion de la paie en Python!
Précautions lors du décapage d'une fonction en python
Ecrire le test dans la docstring python
Afficher une liste d'alphabets en Python 3
Essayez d'envoyer un paquet SYN en Python
Essayez de dessiner une animation simple en Python
Créer une application GUI simple en Python
Ecrire une courte définition de propriété en Python
Dessiner un cœur avec Python Partie 2 (SymPy Edition)
[Python] [Windows] Faites une capture d'écran avec Python
Exécuter l'interpréteur Python dans le script
Comment obtenir stacktrace en python
Ecrire un programme de chiffrement Caesar en Python
Hash en Perl est un dictionnaire en Python
Scraping de sites Web à l'aide de JavaScript en Python
Ecrire une méthode de cupidité simple en Python
Lancer une application Flask dans Python Anywhere
Obtenez un jeton pour conoha avec python
Résoudre ABC165 A, B, D avec Python
[GPS] Créer un fichier kml avec Python
Ecrire un plugin Vim simple en Python 3
Dessinez une structure arborescente en Python 3 à l'aide de graphviz
Générer une classe à partir d'une chaîne en Python
Afficher pyopengl dans le navigateur (python + anguille)
Faisons un calcul de combinaison avec Python
Essayez un tube de programmation fonctionnel en Python