复杂状态 Monad 结构

发布于 2024-12-08 21:13:44 字数 1119 浏览 0 评论 0原文

我仍然是 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

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

我觉得我可以用状态 monad 来清理它,但我不确定如何构造它以允许更改实现 IntStack、BoolStack 等的任何数据类型。

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

感谢您的任何反馈!

I am still a newbie to Haskell and I think I am over my head right now. I have code that looks like the following.

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

My focus (For now ignoring error cases in the functions) is being able to chain together functions like (<=>) and (<+>) assuming that the underlying data type implements the function's required interfaces.

I feel like I can clean this up a lot with a state monad, but I am not sure how to structure it to allow changes to whatever data type that implements IntStack, BoolStack, etc..

I know that this is a horribly vague description, but I feel like the code I have above is probably the absolutely wrong way to go about it.

Thanks for any feedback!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

自在安然 2024-12-15 21:13:44
class IntStack a where
    getIntStack :: a -> [Int]
    putIntStack :: [Int] -> a -> a

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

恭喜,您刚刚发明了镜头!抽象 [Int][Bool] 类型,并使用 data 而不是 class,你会得到一些东西就像

data Lens a b = Lens
    { get :: a -> b
    , put :: b -> a -> a
    }

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

  • 直接从 getIntStack/putIntStackgetBoolStack/putBoolStack 导出投影镜头的能力数据声明
  • 水平组合(运行第一个镜头,然后运行第二个镜头 - 例如,首先从一些较大的结构中挑选一个World,然后从 intStack 中挑选intStack。 code>World) 和垂直组合(并行运行两个镜头,每个镜头在一对的一侧)
  • StateStateT 的一些接口(例如 Lens ab -> State br 类型的东西) -> 声明 a r),这将允许您在 [Bool][Int] 上编写计算,并像在 a 上进行计算一样运行它们世界

所以,看看黑客攻击!有 data-lens 系列,其中包括核心推导能力,以及有状态接口lens 包;和 pointless-lenses 包。可能还有一些我也忘记了。

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

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

Congratulations, you've just invented lenses! Abstract the [Int] and [Bool] types, and use data instead of class, and you get something like

data Lens a b = Lens
    { get :: a -> b
    , put :: b -> a -> a
    }

...which is implemented in half a dozen packages on Hackage. Most offer at least:

  • the ability to derive projection lenses like your getIntStack/putIntStack and getBoolStack/putBoolStack directly from a data declaration
  • horizontal composition (running first one lens, then a second lens -- e.g. first picking a World out of some larger structure, then picking the intStack out of the World) and vertical composition (running two lenses in parallel, each on one side of a pair)
  • some interface with State and StateT (e.g. something of type Lens a b -> State b r -> State a r), which would let you write computations on a [Bool] or [Int] and run them as if they were computations on a World

So, check out hackage! There's the data-lens family, which includes a core, the deriving ability, and the stateful interface; the lens package; and the pointless-lenses package. There are probably some I forgot, too.

破晓 2024-12-15 21:13:44

您可以在状态单子中实现推送和弹出操作,并使用它们来实现您的功能:

popInt :: IntStack c => State c Int
popInt = do
  (x:xs) <- getIntStack <
gt; get
  modify $ putIntStack xs
  return x

pushInt :: IntStack c => Int -> State c ()
pushInt x = do
  xs <- getIntStack <
gt; get
  modify $ putIntStack (x:xs)

(<+>) :: IntStack c => State c ()
(<+>) = do 
  x <- popInt
  x' <- popInt
  pushInt (x + x')

You could implement push and pop operations in the state monad, and use them to implement your functions:

popInt :: IntStack c => State c Int
popInt = do
  (x:xs) <- getIntStack <
gt; get
  modify $ putIntStack xs
  return x

pushInt :: IntStack c => Int -> State c ()
pushInt x = do
  xs <- getIntStack <
gt; get
  modify $ putIntStack (x:xs)

(<+>) :: IntStack c => State c ()
(<+>) = do 
  x <- popInt
  x' <- popInt
  pushInt (x + x')
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文