复杂状态Monad结构

Cha*_*ham 3 monads haskell state-monad

我仍然是Haskell的新手,我想我现在已经超过了我的头脑.我的代码如下所示.

data World = World {
  intStack :: [Int],
  boolStack :: [Bool]
} deriving Show

instance IntStack World where
   getIntStack = intStack
   putIntStack ints (World _ bools) = World ints bools

instance BoolStack World where
    getBoolStack = boolStack
    putBoolStack bools (World ints _) = World ints bools

class IntStack a where
    getIntStack :: a -> [Int]
    putIntStack :: [Int] -> a -> a

class BoolStack a where
    getBoolStack :: a -> [Bool]
    putBoolStack :: [Bool] -> a -> a

(<=>) :: (IntStack c, BoolStack c) => c -> c
(<=>) w = putIntStack xs . putBoolStack ((x == x'):bs) $ w
    where (x:x':xs) = getIntStack w
          bs = getBoolStack w

(<+>) :: (IntStack c) => c -> c
(<+>) w = putIntStack ((x+x'):xs) w
    where (x:x':xs) = getIntStack w
Run Code Online (Sandbox Code Playgroud)

我的重点(现在忽略函数中的错误情况)能够将(<=>)和(<+>)之类的函数链接在一起,假设底层数据类型实现了函数所需的接口.

我觉得我可以使用状态monad清理它很多,但我不知道如何构造它以允许更改实现IntStack,BoolStack等的任何数据类型.

我知道这是一个非常模糊的描述,但我觉得上面的代码可能是绝对错误的方法.

感谢您的任何反馈!

Dan*_*ner 5

class IntStack a where
    getIntStack :: a -> [Int]
    putIntStack :: [Int] -> a -> a

class BoolStack a where
    getBoolStack :: a -> [Bool]
    putBoolStack :: [Bool] -> a -> a
Run Code Online (Sandbox Code Playgroud)

恭喜你,你刚刚发明了镜头!抽象[Int][Bool]类型,而data不是使用class,你会得到类似的东西

data Lens a b = Lens
    { get :: a -> b
    , put :: b -> a -> a
    }
Run Code Online (Sandbox Code Playgroud)

...这是在Hackage上的六个软件包中实现的.大多数提供至少:

  • 能够从数据声明中直接导出投影镜头,如getIntStack/ putIntStackgetBoolStack/putBoolStack
  • 水平构图(运行第一个镜头,然后运行第二个镜头 - 例如首先World从一些较大的结构中挑出一个,然后从中intStack挑出一个World)和垂直构图(并行运行两个镜头,每个镜头一对一侧)
  • 一些接口StateStateT(例如某种类型的东西Lens a b -> State b r -> State a r),它可以让你在a上编写计算[Bool][Int]运行它们,好像它们是在a上的计算一样.World

所以,看看hackage!这个data-lens家族包括核心,衍生能力有状态界面 ; 该透镜封装; 和无意义的镜头包.也许有些我也忘了.