Joe*_*Joe 3 variables haskell loops for-loop immutability
如果我想表达像[只是一个简单的例子]:
int a = 0;
for (int x = 0; x < n; x += 1)
a = 1 - a;
Run Code Online (Sandbox Code Playgroud)
我应该在Haskell中做什么,因为它没有可变的概念?(也许是错的,请参阅:Haskell有变量吗?)
有几个选择.首先,您可以使用朴素递归重写问题:
loop :: Int -> Int
loop n = loop' n 0
where loop' 0 a = a
loop' n a = loop' (n - 1) (1 - a)
Run Code Online (Sandbox Code Playgroud)
接下来,您可以将递归重新表示为折叠:
loop :: Int -> Int
loop n = foldr (\a _ -> 1 - a) 0 [0..n]
Run Code Online (Sandbox Code Playgroud)
或者您可以使用State
模拟for循环:
import Control.Monad
import Control.Monad.State
loop :: Int -> Int
loop n = execState (forM_ [0..n]
(\_ -> modify (\a -> 1 - a))) 0
Run Code Online (Sandbox Code Playgroud)
通常,在过程语言中使用循环执行的重复是通过Haskell中的递归完成的.在这种情况下,您应该考虑循环的结果.它似乎在0和1之间交替.在Haskell中有几种方法可以做到这一点.一种方法是
alternatingList n = take n alternating0and1
alternating0and1 = 0 : alternating1and0
alternating1and0 = 1 : alternating0and1
Run Code Online (Sandbox Code Playgroud)
在Haskell而不是使用循环中,您可以组合标准库函数和/或您自己的递归函数来实现所需的效果.
在您的示例代码中,您似乎设置a
为0或1,具体取决于是否n
为偶数(如果我诚实,则以相当混乱的方式).要在Haskell中实现相同的目的,你需要写:
a =
if even n
then 0
else 1
Run Code Online (Sandbox Code Playgroud)
另外一个选项:
iterate (\a -> 1-a) 0 !! n
-- or even
iterate (1-) 0 !! n
Run Code Online (Sandbox Code Playgroud)
该代码段iterate (\a -> 1-a) 0
生成一个无限的惰性列表,其中包含从 开始0
并重复应用该函数获得的所有值(\a -> 1-a)
。然后!! n
取第 n 个元素。
老实说,在这种情况下,我还会寻找一个更严格的定义,iterate
它不会产生这么多懒惰的 thunk。
其他答案已经解释了如何在 Haskell 中从功能上解决这样的问题。
但是,Haskell 确实具有ST操作和STRef形式的可变变量(或引用)。使用它们通常不是很漂亮,但它确实允许您在 Haskell 中忠实地表达命令式的、可变的代码,如果您真的愿意的话。
只是为了好玩,以下是您可以如何使用它们来表达您的示例问题。
(为方便起见,以下代码还使用了monad-loops包中的whileM_。)
import Control.Monad.Loops
import Control.Monad.ST
import Data.STRef
-- First, we define some infix operators on STRefs,
-- to make the following code less verbose.
-- Assignment to refs.
r @= x = writeSTRef r =<< x
r += n = r @= ((n +) <$> readSTRef r)
-- Binary operators on refs. (Mnemonic: the ? is on the side of the ref.)
n -? r = (-) <$> pure n <*> readSTRef r
r ?< n = (<) <$> readSTRef r <*> pure n
-- Armed with these, we can transliterate the original example to Haskell.
-- This declares refs a and x, mutates them, and returns the final value of a.
foo n = do
a <- newSTRef 0
x <- newSTRef 0
whileM_ (x ?< n) $ do
x += 1
a @= (1 -? a)
readSTRef a
-- To run it:
main = print =<< stToIO (foo 10)
Run Code Online (Sandbox Code Playgroud)