Haskell 如何将要执行的可选操作序列链接到;变量";?

Haskell 如何将要执行的可选操作序列链接到;变量";?,haskell,Haskell,是否有一些模式可以减少重复和一致使用ifs 让我解释一下。有些算法本质上是程序性的,依赖于随时间修改变量/对象/数组的状态。在Haskell中实现这一点并不困难,我们只是为每个步骤声明一个不同的变量。问题是,有时我们只想在变量满足条件时更改变量的状态,这通常需要大量的ifs或cases 因此,考虑下面的相当丑陋的代码: import Data.List (foldl') import qualified Data.Se

是否有一些模式可以减少重复和一致使用
if
s

让我解释一下。有些算法本质上是程序性的,依赖于随时间修改变量/对象/数组的状态。在Haskell中实现这一点并不困难,我们只是为每个步骤声明一个不同的变量。问题是,有时我们只想在变量满足条件时更改变量的状态,这通常需要大量的
if
s或
case
s

因此,考虑下面的相当丑陋的代码:

import           Data.List                              (foldl')
import qualified Data.Sequence as Seq
import           Data.Sequence                          ((|>))

sequencialOps :: Int -> (Int, Seq.Seq (Either Bool Int))
sequencialOps init = foldl' manySteps (init, Seq.empty) [0..init]
  where
    manySteps (val, valseq) time = if time `mod` 2 == 0
                                     then intermediateSteps (2*val-9)
                                     else (val, valseq)
      where
        intermediateSteps someNum = (newnum3-1, numseq3 |> Right (newnum2-1))
          where
            (newnum1, numseq1) = if someNum > 10 || someNum < 12
                                    then (-someNum `div` 3, valseq |> Left True)
                                    else (someNum, valseq)
            (newnum2, numseq2) = if someNum `mod` 3 == 0
                                    then (-(someNum `mod` 970), numseq1 |> Right newnum1)
                                    else (newnum1, numseq1)
            (newnum3, numseq3) = if someNum == 0
                                    then (time, numseq2 |> Left False)
                                    else (newnum2, numseq2)

main = print $ sequencialOps 6

代码是有效的,但它有点难以理解,太多级别的作用域和许多
if
s和
case
s。T_T

是的,您可以使用monad编写外观更干净的代码,以修改状态:

sequentialOps :: Int -> (Int, Seq.Seq (Either Bool Int))
sequentialOps init = run (traverse_ manySteps [0..init])
  where
    manySteps time = when (even time) $ do
      val <- get
      let someNum = 2*val-9
      when (someNum > 10 || someNum < 12) $ do
        put (-someNum `div` 3)
        log (Left True)
      when (someNum `mod` 3 == 0) $ do
        gets Right >>= log
        put (-(someNum `mod` 970))
      num2 <- get
      when (someNum == 0) $ do
        log (Left False)
        put time
      modify pred
      log (Right (num2-1))
    log = tell . Seq.singleton
    run = runWriter . flip execStateT init

你到底想用这段代码做什么?如果我有这个想法,我可以更轻松地向您展示如何将其转换为功能性样式。

当听起来应该可以工作时,
状态
单子一起使用。谢谢。实际上,我将上面的代码作为一个较长函数的示例来编写。我不想在这里复制这个函数,因为它有点长,但是我要更新这个问题。
sequentialOps :: Int -> (Int, Seq.Seq (Either Bool Int))
sequentialOps init = run (traverse_ manySteps [0..init])
  where
    manySteps time = when (even time) $ do
      val <- get
      let someNum = 2*val-9
      when (someNum > 10 || someNum < 12) $ do
        put (-someNum `div` 3)
        log (Left True)
      when (someNum `mod` 3 == 0) $ do
        gets Right >>= log
        put (-(someNum `mod` 970))
      num2 <- get
      when (someNum == 0) $ do
        log (Left False)
        put time
      modify pred
      log (Right (num2-1))
    log = tell . Seq.singleton
    run = runWriter . flip execStateT init
sequentialOps :: Int -> (Int, Seq.Seq (Maybe Int))
sequentialOps init = run (replicateM_ (1 + init `div` 2) manySteps)
  where
    manySteps = do
      val <- get
      let someNum = 2*val-9
      put (-someNum `div` 3)
      log Nothing
      when (someNum `mod` 3 == 0) $ do
        gets Just >>= log
        put (-(someNum `mod` 970))
      modify pred
      gets Just >>= log
    log = tell . Seq.singleton
    run = runWriter . flip execStateT init