是否可以创建一个函数:
liftState :: (MonadState s ms, MonadState t mt) => Lens' s t -> mt a -> ms a
如果Lens' s t
可以在t
内获取并设置s
,则会将状态MonadState
的{{1}}计算提升为t
1}}使用状态MonadState
进行计算?
如何在不同的州类型上运行子计算?
答案 0 :(得分:3)
一般说明:使用Lens
/ Getter
/ Prism'
等作为函数的参数类型很少是个好主意。请记住,那些是真正普遍量化的类型(在lens
,Van Laarhoven类型∀ f . (a -> f b) -> s -> f t
),因此接受它们的函数是rank-2多态,这对于类型检查器来说是相当痛苦的。相反,您应该使用其中一个具体的光学类型,它们位于lens
库中,前缀为字母A
。即你想成功吗
liftState :: (MonadState s ms, MonadState t mt) => ALens' s t -> mt a -> ms a
虽然duplode已经评论过你应该真的只使用zoom
,但是自己实现这个不太通用的版本也不难:
liftState l m = state $ \s -> case runState m $ s ^# l of
(a, b) -> (a, s & l #~ b)
此处,^#
and #~
与知名度较高的^.
和.~
运算符基本相同,但实际上分别需要AGetter
和ASetter
的运算符除外。 (与Lens'
兼容,但与ALens'
不兼容;在更复杂的功能中,您可以使用cloneLens
)来解决此问题。