Haskell - for循环

问题描述 投票:3回答:5

如果我想表达像[只是一个简单的例子]:

int a = 0;
for (int x = 0; x < n; x += 1)
    a = 1 - a;

我应该在Haskell中做什么,因为它没有可变的概念? (也许是错的,请参阅:Does Haskell have variables?

loops variables for-loop haskell immutability
5个回答
7
投票

通常,在Haskell中使用recursion完成您在过程语言中使用循环执行的重复。在这种情况下,您应该考虑循环的结果。它似乎在0和1之间交替。在Haskell中有几种方法可以做到这一点。一种方法是

alternatingList n = take n alternating0and1
alternating0and1 = 0 : alternating1and0
alternating1and0 = 1 : alternating0and1

9
投票

有几个选择。首先,您可以使用朴素递归重写问题:

loop :: Int -> Int
loop n = loop' n 0
  where loop' 0 a = a
        loop' n a = loop' (n - 1) (1 - a)

接下来,您可以将递归重新表示为折叠:

loop :: Int -> Int
loop n = foldr (\a _ -> 1 - a) 0 [0..n]

或者您可以使用State来模拟for循环:

import Control.Monad
import Control.Monad.State

loop :: Int -> Int
loop n = execState (forM_ [0..n] 
                      (\_ -> modify (\a -> 1 - a))) 0

5
投票

在Haskell而不是使用循环中,您可以组合标准库函数和/或您自己的递归函数来实现所需的效果。

在您的示例代码中,您似乎将a设置为0或1,具体取决于n是否为偶数(如果我诚实,则会以相当混乱的方式)。要在Haskell中实现相同的目的,你需要写:

a =
  if even n
  then 0
  else 1

4
投票

另外一个选项:

iterate (\a -> 1-a) 0 !! n
-- or even
iterate (1-) 0 !! n

片段iterate (\a -> 1-a) 0生成从0开始并重复应用函数(\a -> 1-a)获得的所有值的无限懒惰列表。然后!! n采用第n个元素。

说实话,在这种情况下,我也会寻找更严格的iterate定义,这种定义不会产生如此多的懒惰。


3
投票

其他答案已经解释了如何在Haskell中如何在功能上处理这样的问题。

但是,Haskell确实有ST行为和STRef形式的可变变量(或引用)。使用它们通常不是很漂亮,但它确实允许你在Haskell中忠实地表达命令式,变量变异代码,如果你真的想要的话。

只是为了好玩,以下是如何使用它们来表达您的示例问题。

(为方便起见,下面的代码也使用了whileM_包中的monad-loops。)

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)
© www.soinside.com 2019 - 2024. All rights reserved.