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