我的程序的状态由三个值组成,a、b和c类型为A、B和C。不同的函数需要访问不同的值。我希望使用State monad编写函数,以便每个函数只能访问它需要访问的状态的各个部分。
我有以下四种功能:
f :: State (A, B, C) x
g :: y -> State (A, B) x
h :: y -> State (B, C) x
i :: y -> State (A, C) x下面是如何在g中调用f
f = do
-- some stuff
-- y is bound to an expression somewhere in here
-- more stuff
x <- g' y
-- even more stuff
where g' y = do
(a, b, c) <- get
let (x, (a', b')) = runState (g y) (a, b)
put (a', b', c)
return x这个g'函数是一个丑陋的样板,它除了弥合(A, B, C)和(A, B)类型之间的差距之外,什么也不做。它基本上是g的一个版本,它在三元组状态下运行,但保持第三个元组项不变。我正在寻找一种没有样板的情况下编写f的方法。也许是这样的:
f = do
-- stuff
x <- convert (0,1,2) (g y)
-- more stuff其中,convert (0,1,2)将State (a, b) x类型的计算转换为State (a, b, c) x类型。同样,对于所有类型的a、b、c、d
convert (2,0,1)将State (c,a) x转换为State (a,b,c) xconvert (0,1)将State b x转换为State (a,b) xconvert (0,2,1,0)将State (c,b) x转换为State (a,b,c,d) x我的问题:
f和g ),F⊆G或G⊆F ( F是f所需的状态值集,G是g所需的状态值集)才能工作。我是不是弄错了?(请注意,我的示例不满足此属性。例如,G = {a, b}和H = {b, c}。两者都不是对方的子集。)(我提到的函数应该是这样的。)
convert_0_1_2 :: State (a, b) x -> State (a, b, c) x
convert_0_1_2 f = do
(a, b, c) <- get
let (x, (a', b')) = runState f (a, b)
put (a', b', c)
return x
convert_0_2_1_0 :: State (c, b) x -> State (a, b, c, d) x
convert_0_2_1_0 f = do
(a, b, c, d) <- get
let (x, (b', c')) = runState f (b, c)
put (a, b', c', d)
return x发布于 2015-11-26 17:10:03
您可以使用lens-family中的缩放或lens包与tuple-lenses包进行缩放:简化的zoom类型是:
zoom :: Lens' s a -> State a x -> State s x因此,zoom使用较小的状态运行计算。Lens用于指定较小状态a在较大状态s中的位置。
使用这两个包,您可以运行g、h和i,如下所示:
f :: State (A,B,C) x
f = do
zoom _12 g -- _12 :: Lens' (A,B,C) (A,B)
zoom _23 h -- _23 :: Lens' (A,B,C) (B,C)
zoom _13 i -- _13 :: Lens' (A,B,C) (A,C)发布于 2015-11-26 19:59:23
如果你不想在元组上大惊小怪,你可以用一种有记录的“优雅”方法。在lens包中有一些很好的模板Haskell来支持这一点,但是您也可以手工完成。这样做的目的是为状态的每个部分创建至少一个类:
class HasPoints s where
points :: Lens' s Int
class ReadsPoints s where
getPoints :: Getter s Int
default getPoints :: HasPoints s => Getter s Int
getPoints = points
class SetsPoints s where
setPoints :: Setter' s Int
...然后,每个操纵状态的函数都有一个类型签名,如下所示
fight :: (HasPoints s, ReadsHealth s) => StateT s Game Player具有此特殊签名的操作可以完全访问各个点,并可只读访问健康。
https://stackoverflow.com/questions/33935835
复制相似问题