Beim Programmieren möchte ich oft "den Status mit mehreren Funktionen teilen".
Derzeit ist es besser, aus verschiedenen Lösungen das Beste auszuwählen, als globale Variablen zu verwenden oder den Zeiger ohne nachzudenken weiterzuleiten.
Daher werde ich die Methode, den Zustand mit mehreren Funktionen zu teilen, zusammen mit den Vor- und Nachteilen zusammenfassen, so viel ich mir vorstellen kann.
Verwenden Sie Python als Beispielcode und Racket (eine Art Schema), wenn Sie nicht in Python schreiben können. weil ich mag.
state = "initial state"
def fuga0():
#Ändern Sie nach Bezugnahme auf den Zustand
global state
print(f"fuga0: {state}")
state = "another state"
return "result of fuga0"
def fuga1():
#Beziehen Sie sich auf den Zustand
print(f"fuga1: {state}")
def hoge():
print(fuga0())
fuga1()
print(f"last: {state}")
hoge()
Ergebnis (Folgendes wird weggelassen)
fuga0: initial state
result of fuga0
fuga1: another state
last: another state
Kein sehr empfohlener Schreibstil.
from dataclasses import dataclass
from typing import Any
#Ein Zeiger, an den dieser Typ weitergeleitet wird
@dataclass
class Box:
value: Any
def fuga0(box):
print(f"fuga0: {box.value}")
box.value = "another state"
return "result of fuga0"
def fuga1(box):
print(f"fuga1: {box.value}")
def hoge(box):
print(fuga0(box))
fuga1(box)
print(f"last: {box.value}")
b = Box("initial state")
hoge(b)
Im Falle einer Konstante sollte der Wert anstelle des Zeigers Bucket-Relaying sein.
Es handelt sich um einen sogenannten funktionalen Schreibstil, und der Status ändert sich im Code nicht.
def fuga0(state):
print(f"fuga0: {state}")
return "result of fuga0", "another state"
def fuga1(state):
print(f"fuga1: {state}")
def hoge(state):
result, new_state = fuga0(state)
print(result)
fuga1(new_state)
print(f"last: {new_state}")
hoge("initial")
Eine Methode, die häufig in objektorientierten Sprachen verwendet wird. Legen Sie den Status fest, für den Sie eine Mitgliedsvariable freigeben möchten.
class Hoge:
def __init__(self):
self._state = "initial state"
def _fuga0(self):
print(f"fuga0: {self._state}")
self._state = "another state"
return "result of fuga0"
def _fuga1(self):
print(f"fuga0: {self._state}")
def __call__(self):
print(self._fuga0())
self._fuga1()
print(f"last: {self._state}")
hoge = Hoge()
hoge()
Nah an objektorientiert.
def create_hoge():
state = "initial"
def fuga0():
nonlocal state
print(f"fuga0: {state}")
state = "another state"
return "result of fuga0"
def fuga1():
print(f"fuga1: {state}")
def hoge():
print(fuga0())
fuga1()
print(f"last: {state}")
return hoge
create_hoge()()
Glocal Variable
Muster meiner Gedanken. Erstellen Sie eine Variable, die nur in mit verwendet werden kann. Siehe den Link für Details.
param.py
_param = None
_initialized = False
@contextmanager
def parametrize(data):
global _param
global _initialized
before = _param
before_initialized = _initialized
_param = data
_initialized = True
try:
yield
finally:
_param = before
_initialized = before_initialized
def set_param(data):
if _initialized:
global _param
_param = data
else:
raise RuntimeError
def get_param():
if _initialized:
return _param
else:
raise RuntimeError
from param import get_param, set_param, parametrize
def fuga0():
print(f"fuga0: {get_param()}")
set_param("another state")
return "result of fuga0"
def fuga1():
print(f"fuga0: {get_param()}")
def hoge():
print(fuga0())
fuga1()
print(f"last: {get_param()}")
with parametrize("initial state"):
hoge()
Was ist Monade? Was ist Staatsmonade? Bitte googeln Sie für so etwas.
Schreiben wir mit Racket. Ich bin mir ein wenig unsicher über die Implementierung von ...
;Definition der Staatsmonade von hier
(require (prefix-in base: racket/base))
(require data/functor)
(require data/applicative)
(require data/monad)
(struct result (value state) #:transparent)
(struct state (f)
#:methods gen:functor
[(define (map g x)
(state (λ (s)
(match-define (result v ss) (run x s))
(result (g v) ss))))]
#:methods gen:applicative
[(define (pure _ x)
(state (λ (s) (result x s))))
(define (apply f xs)
(define (get-args xs s)
(match xs
[(cons x rest)
(match-define (result xv xs) (run x s))
(match-define (result args argss) (get-args rest xs))
(result (cons xv args) argss)]
[_ (result `() s)]))
(state (λ (s)
(match-define (result fv fs) (run f s))
(match-define (result args argss) (get-args xs fs))
(result (base:apply fv args) argss))))]
#:methods gen:monad
[(define (chain f x)
(state (λ (s)
(match-define (result xv xs) (run x s))
(match-define (result fv fs) (run (f xv) xs))
(result fv fs))))])
(define (run m s) ((state-f m) s))
(define get
(state (λ (s) (result s s))))
(define (set ns)
(state (λ (s) (result s ns))))
;Definition bis hierher
(define fuga0
(do [x <- get]
(pure (printf "fuga0: ~a\n" x))
(set "another state")
(pure "result of fuga0")))
(define fuga1
(do [x <- get]
(pure (printf "fuga1: ~a\n" x))))
(define hoge
(do [x <- fuga0]
(pure (displayln x))
fuga1
[y <- get]
(pure (printf "last: ~a\n" y))))
(run hoge "initial state")
Verwenden Sie für Konstanten die Reader-Monade.
Es ist ein ziemlicher Schmerz in Python, aber wenn Sie Ihr Bestes geben, sieht es so aus.
#Staatliche Monadendefinition von hier
from typing import Callable, TypeVar, Generic, Tuple
S = TypeVar("S") #Zustandstyp
R = TypeVar("R") #Rückgabetyp
A = TypeVar("A") #Neuer Rückgabetyp
class State(Generic[S, R]):
def __init__(self, f: Callable[[S], Tuple[S, R]]):
self._f = f
def run(self, state: S) -> Tuple[S, R]:
return self._f(state)
@staticmethod
def of(value: R):
return State(lambda s: (value, s))
def flatmap(self, g: Callable[[R], State[S, A]]) -> State[S, A]:
def _new(state):
f_ret, f_state = self.run(state)
return g(f_ret).run(f_state)
return State(_new)
def map(self, g: Callable[[R], A]) -> State[S, A]:
return self.flatmap(lambda x: State.of(g(x)))
def then(self, m: State[S, A]) -> State[S, A]:
return self.flatmap(lambda _: m)
def value(self, v: A) -> State[S, A]:
return self.map(lambda _: v)
get_m = State(lambda s: (s, s))
def set_m(new_state):
return State(lambda s: (s, new_state))
#Bisherige Definition der staatlichen Monade
fuga0 = (get_m
.map(lambda v: print(f"fuga0: {v}"))
.then(set_m("another_state"))
.value("result of fuga0"))
fuga1 = (get_m
.map(lambda v: print(f"fuga1: {v}")))
hoge = (fuga0
.map(print)
.then(fuga1)
.then(get_m)
.map(lambda v: print(f"last: {v}")))
hoge.run("initial state")
Was ist begrenzte Fortsetzung? Warum können Sie mit Statusänderungen umgehen? Siehe Asai-senseis Tutorial.
(require racket/control)
(define (get)
(shift k
(λ (x)
((k x) x))))
(define (set s)
(shift k
(λ (x)
((k x) s))))
(define (run m s)
((reset
(let ([ret (m)])
(λ (_) ret))) s))
(define (fuga0)
(printf "fuga0: ~a\n" (get))
(set "another state")
"result of fuga0")
(define (fuga1)
(printf "fuga1: ~a\n" (get)))
(define (hoge)
(displayln (fuga0))
(fuga1)
(printf "last: ~a\n" (get)))
(run hoge "initial state")
Jeder sagt jeder anders.
Anstatt sich an das zu halten, was Sie als Programmierer wissen, erhöhen Sie die Anzahl der Werkzeuge und verwenden Sie sie ordnungsgemäß.
Außerdem enthält die Standard-Python-Bibliothek contextvars. Ich habe es diesmal nicht erwähnt, weil es anscheinend asynchron gemacht wurde.
Recommended Posts