Je voudrais utiliser Python. Et quand il s'agit de monades, Maybe est célèbre.
Peut-être est-il relativement facile à comprendre et il est facile de le mettre en pratique dans différentes langues, de sorte que certaines personnes l'implémentent par eux-mêmes. Je pense que ça va arriver. Mais, Je pense qu'il vaut mieux comprendre de la monade d'État J'ai trouvé un article comme celui-là.
Je vais donc mettre en place la monade d'État. Faisons une calculatrice pour l'addition, la soustraction, la multiplication et la division en utilisant stack avec Haskell Monade d'État de Haskell (1) - État d'imitation 6ème monade d'État pour l'utilisation de "l'État" local J'ai lu quelque chose comme ça et j'ai augmenté ma conscience.
Je ne peux pas nier le sentiment qu'il y a tant d'articles existants. En outre, l'explication comprenant l'article de référence C'est concret et facile à comprendre. Cependant, pour cette raison, dans la partie implémentation de la pile Ikansen J'y ai mis trop d'efforts et j'ai senti qu'il était difficile de saisir l'essence de l'État.
Donc, en utilisant un langage légèrement différent et en le réimplémentant vous-même, en tant que mécanisme plus abstrait Cherchons à saisir la monade d'État.
Donc, ici, je ferai référence à l'implémentation Haskell sans penser à rien de plus. Pour le moment, j'aimerais apprendre l'essentiel de la monade d'État en la portant en Python telle quelle. Python est un langage de type dynamique, mais s'il semble difficile à comprendre, ajoutons des annotations de type avec des commentaires opportuns.
Regardons maintenant la définition de Haskell.
newtype State s a = State { runState :: s -> (a, s) }
instance Monad (State s) where
return a = State $ \s -> (a, s)
m >>= k = State $ \s -> let
(a, s') = runState m s
in runState (k a) s'
En regardant la définition, State semble être une monade avec la fonction s-> (a, s)
à l'intérieur.
C'est l'État, n'est-ce pas?
Dans la valeur de retour taple, a sur la gauche est le résultat du changement, et s sur la droite est l'état après le changement.
D'un point de vue linguistique procédural, celui-ci donne une impression étrange!
À propos, pour ceux qui ne connaissent pas la grammaire de Haskell,
Haskell déclare les expressions lambda sous la forme \ argument-> expression
.
De plus, le mot-clé let
est une expression let, et les variables sont liées sous let.
ʻIn` C'est comme renvoyer l'expression suivante.
Je le veux aussi pour Python (je l'ai fait http://qiita.com/hatchinee/items/1face0ffd5466de1ad97).
Et il existe une autre définition d'une fonction qui obtient et réécrit l'état. Ceci est déclaré comme une classe de type appelée MonadState.
class (Monad m) => MonadState s m | m -> s where
get :: m s
put :: s -> m ()
instance MonadState s (State s) where
get = State $ \s -> (s, s)
put s = State $ \_ -> ((), s)
La puissance d'Haskell est faible, alors qu'est-ce qu'une classe de type ou une instance est une POO? Et diverses questions Il disparaît quand il flotte (* myuon_myon expliqué dans les commentaires. Merci!) Traduisez la partie fonction sans souci.
Commençons par State pour le moment.
class State(object):
def __init__(self, a):
''' private '''
self.run_state = a
@classmethod
def ret(_, a):
''' return
'''
return State(lambda s: (a, s))
def bind(self, func):
''' >>=
'''
def _(a):
v, st = self.run_state(a)
return func(v).run_state(st)
return State(_)
def __rshift__(self, func):
''' define >> as bind '''
return self.bind(func)
runState est un membre self.run_state
Puisque return est un mot réservé en Python, déclarez-le comme une méthode de classe appelée ret.
>> =
est appelé >>
car il ressemble à une méthode de liaison ou quelque chose de similaire.
Rendez-le disponible dans l'opérateur.
Je pense que «>>» a été utilisé par un autre opérateur Monad, donc si vous pensez que c'est dangereux, vous pouvez en utiliser un autre.
class MonadState(object):
@classmethod
def get(_):
''' get = State $ \s -> (s, s)
'''
return State(lambda s: (s, s))
@classmethod
def put(_, a):
''' put s = State $ \_ -> ((), s)
'''
return State(lambda s: (None, a))
État de la Monade. J'ai essayé de mettre la définition en Haskell dans le commentaire, mais elle peut être implémentée presque telle quelle. Utilisons maintenant ces implémentations pour voir si la réécriture et la récupération d'état fonctionnent.
>>> (MonadState.put(12) >> (lambda _: \
MonadState.get())).run_state(13)
(12, 12)
>>> (MonadState.put(12) >> (lambda _: \
MonadState.get() >> (lambda i: \
MonadState.put(i * 2)))).run_state(13)
(None, 24)
Je pense que cela fonctionnera si vous l'exécutez comme une invite ou un doctest.
La monade d'État consiste probablement à faire abstraction de la procédure en synthétisant la fonction et en y donnant l'état. Je pensais que c'était un mécanisme qui pouvait avoir des résultats ou des effets secondaires sur la maladie.
Cela peut prendre un certain temps à comprendre car le comportement de get and put et la partie composition dans bind sont compliqués. Que se passe-t-il lorsque vous essayez de l'implémenter vous-même ou de créer quelque chose à l'aide de State Je pense que vous pourrez le sentir dans votre cœur.
Maintenant que je l'ai ressenti dans mon cœur, faisons quelque chose de bien en utilisant la monade d'État. En parlant de piles, je vais faire une calculatrice polonaise inversée.
Pour le moment, définissez une fonction auxiliaire qui convertit une chaîne de caractères en opérateur.
from operator import add, sub, div, mul, concat
_OP_HOLDER = {
'+': add,
'-': sub,
'*': mul,
'/': div,
}
def _op(st):
op = _OP_HOLDER[st]
def _(x1, x2):
'''Puisqu'il est difficile de contrôler l'ordre des pops, inversez ici'''
print x2, st, x1
return [op(x2, x1)]
return _
def _concat(xs, ys):
print xs, ys
return concat(xs, ys)
def _is_valid_operator(v):
return v in ['+', '-', '*', '/']
Ensuite, implémentez la partie push ou calcul sur la calculatrice.
class Calculator(object):
@classmethod
def push(_, val):
if _is_valid_operator(val):
return \
MonadState.get() >> (lambda x:
MonadState.put(
_concat(
x, _op(val)(x.pop(), x.pop()))))
else:
return \
MonadState.get() >> (lambda x:
MonadState.put(_concat(x, [val])))
@classmethod
def run(_, stk):
_, ret = stk.run_state([])
return ret.pop()
C'est gênant, donc la partie pop accède directement à la liste interne.
Testons-le.
if __name__ == '__main__':
C = Calculator
print '1 2 + 4 5 + *'
calc = \
C.push(1) >> (lambda _:
C.push(2) >> (lambda _:
C.push('+') >> (lambda _:
C.push(4) >> (lambda _:
C.push(5) >> (lambda _:
C.push('+') >> (lambda _:
C.push('*')))))))
assert C.run(calc) == (1 + 2) * (4 + 5)
'''
1 2 + 4 5 + *
[] [1]
[1] [2]
1 + 2
[] [3]
[3] [4]
[3, 4] [5]
4 + 5
[3] [9]
3 * 9
[] [27]
Devrait être imprimé comme!
'''
print '\n5 4 3 - +'
calc = \
C.push(5) >> (lambda _:
C.push(4)) >> (lambda _:
C.push(3)) >> (lambda _:
C.push('-')) >> (lambda _:
C.push('+'))
assert C.run(calc) == (5 + 4 - 3)
print '\n6 2 + 5 3 - 2 * /'
calc = \
C.push(6) >> (lambda _:
C.push(2) >> (lambda _:
C.push('+') >> (lambda _:
C.push(5) >> (lambda _:
C.push(3) >> (lambda _:
C.push('-') >> (lambda _:
C.push(2) >> (lambda _:
C.push('*') >> (lambda _:
C.push('/')))))))))
assert C.run(calc) == (6 + 2) / ((5 - 3) * 2)
Comment c'est? Je suis nouveau dans l'implémentation d'une calculatrice de notation polonaise inversée, donc je ne suis pas sûr. Je pense que ça marche bien.
La partie opération fonctionne avec ou sans fonctions d'ordre supérieur. Si vous utilisez des fonctions d'ordre supérieur, il semble que vous puissiez également effectuer des calculs (tels que la somme) en utilisant l'agrégation des résultats de chaque opération.
Cela ne semble pas être directement pratique pour écrire Python, mais je l'ai apprécié comme exercice cérébral. Merci pour votre soutien.
Si vous aimez cela, veuillez également le vérifier (Résumé des articles sur le codage de Python semblable à la magie noire que j'ai écrit jusqu'à présent -à propos-python)))
Recommended Posts