问题描述
我正在研究如何为我的 state monad 类事物定义 flatmap
。
class State(Protocol[T_co]):
@abstractmethod
def __call__(self: S,i: int) -> tuple[T_co,S]:
...
A State
封装了状态。这是unit
def unit(t: T) -> State[T]:
return lambda _: (t,unit(t))
我从他们使用 State[S,A] = S -> (A,S)
的书中得到了设计,但我发现它有点麻烦(并且还需要额外的参数 i
),所以这里的 class Foo(State[int])
几乎就像State[Foo,int]
。我想知道我简化它的尝试是否使它不再是一个 monad。
我尝试过类似的东西
def flatmap(f: Callable[[T],State[U]],s: State[T]) -> State[U]:
def stateful(i: int) -> tuple[U,State[U]]:
t,s_new = s(i)
u,su = f(t)(i)
return u,flatmap(f,s_new) # or u,su
return stateful
但尽管我认为这满足恒等式(尚未检查结合性),但我希望同时使用新状态 s_new
和 su
。
为了完整起见,这里有一个恐怖片,它是书中 flatmap
的字面翻译,该书使用 S -> (A,S)
到我的案例,并带有一个额外的参数 i: int
。我对它会起作用的期望为零
def flatmap(f: Callable[[T],s: State[T]) -> State[U]:
class _State(State[U]):
def __call__(self,i: int) -> tuple[U,_State]:
x,y = type(s).__call__(self,i)
return type(f(x)).__call__(y,i)
return _State()
解决方法
我认为这是不可能的。状态的标准定义使用 S -> (A,S)
。添加一个额外的参数 (S,int) -> (A,S)
可能会也可能不会破坏它,但可能会是这样一个事实,即 (S,S)
可以接受任何东西作为它的第一个参数,而 {{1} 的(子类)的实例}} 只能接受该类的一个实例作为 class State
。也就是说,我将自己限制为只能接受自己作为第一个参数的 self
。这究竟是如何排除定义 State
我仍在努力解决的。