2016-08-24 103 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)