2016-08-24 105 views
2

如果我想表达的东西像[只是一个简单的例子]:哈斯克尔 - for循环

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

我应该在Haskell做,因为它不具有可变的概念?(可能有误,请参阅:Does Haskell have variables?

+1

为此,您可以与[递归](http://learnyouahaskell.com/recursion)。 –

+1

p.s. Haskell有变量。他们的行为不同于程序语言。 –

+0

@ Code-Apprentice uuuh,like'rec x a = if x Joe

回答

5

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

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

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

在您的示例代码中,您似乎将a设置为0或1,具体取决于n是否为偶数(如果我诚实地说,这种方式相当混乱)。为了实现在Haskell一样,你会写:

a = 
    if even n 
    then 0 
    else 1 
7

有几个选项。首先,你可以重写与天真的递归问题:

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 
3

另一种选择:

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

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

说实话,在这种情况下,我还会寻找一个更严格的定义iterate,它不会产生这么多懒惰的thunk。

2

其他答案已经解释了如何在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)