2011-05-31 106 views
2

如何將這部分C代碼翻譯成Haskell?據我所知,我必須使用國家monad,但我不知道如何。將C代碼翻譯成Haskell

int x = 1; 
int y = 2; 
x = x * y; 
y = y + x; 
+2

你最終的目標是什麼? – Gabe 2011-05-31 19:10:48

+0

我只是想修改變量的值。 – 2011-05-31 19:12:19

+3

如果你有更多的上下文,這將有所幫助。你爲什麼要重新分配x和y?在你的代碼中,你根本不需要這樣做,所以......當翻譯僅僅是'x = 2; y = 4' – mentics 2011-05-31 19:12:48

回答

6

字面翻譯就是使用IORefs

import Data.IORef 

main :: IO() 
main = do x <- newIORef 1 
      y <- newIORef 2 
      y_val <- readIORef y 
      modifyIORef x (\v -> v * y_val) 
      x_val <- readIORef x 
      modifyIORef y (\v -> v + x_val) 

正如你所看到的,命令式編程是在Haskell難看。這是故意的,哄你使用功能風格。您可以定義一些輔助功能,雖然,使這個更愜意:

import Data.IORef 

-- x := f x y 
combineToR :: (a -> t -> a) -> IORef a -> IORef t -> IO() 
combineToR f x y = do y_val <- readIORef y 
         modifyIORef x (\v -> f v y_val) 

addTo :: Num a => IORef a -> IORef a -> IO() 
addTo = combineToR (+) 

multWith :: Num a => IORef a -> IORef a -> IO() 
multWith = combineToR (*) 

main :: IO() 
main = do x <- newIORef 1 
      y <- newIORef 2 
      multWith x y 
      addTo y x 
+2

您的初始'main',應該是'y_val < - readIORef x' - 就像現在一樣,它會放出'x'。 – rampion 2011-06-01 17:41:36

+0

@rampion謝謝,修復 – 2011-06-01 20:27:28

6

函數式語言的重點在於您不這樣做,創造新的價值或使用遞歸。

如果你喜歡只打印這些值,

x = 1 
y = 2 
a = x*y 
b = y+x 

main = do 
      putStrLn ("x*y: " ++ a) 
      putStrLn ("y+x: " ++ b) 

如果這是家庭作業,請其標記爲如此,我會改變我的答案。

+1

這確實是一項家庭作業。其中的一部分,更加精確。我必須在Haskell中翻譯一個用C語言實現的電話簿。我只想看看如何執行set/get操作。 – 2011-05-31 19:26:16

+2

@Bigba Mbum你可能不需要它們。在Haskell中,很少使用set和get操作。大多數可以用純粹的方式來定義。 – fuz 2011-05-31 19:30:18

+1

get和set是非常必要的,除非你的老師知道你住在哪裏,喝過量的伏特加和看恐怖片,否則我不會使用它。 – 2011-06-01 04:04:44

8

假設,你有兩個整數作爲國家:

f = do put (1,2) 
     modify (\(x,y) -> (x*y,y)) 
     modify (\(x,y) -> (x,y+x)) 

是這樣的,你想要什麼?

+0

谷歌在查詢「set and get in haskell」上的第一個結果讓我到http://www.haskell.org/haskellwiki/State_Monad。我想翻譯的代碼看起來就是那裏給出的具體例子之一。 – 2011-05-31 19:23:36

+4

注意,這是從C版本,在C代碼X略有不同的是修改之前* * y設定,不同時,那麼你可能需要把'(1,2)= >>修改(\( x',y) - >(x * y,y))>> =修改(\(x,y) - >(x,y + x))' – rampion 2011-05-31 20:48:19

1

如果您發現有一個元組的「可變」的變量,你可以在上面定義的轉換操作和「鏈」一起:

vars x y = (x,y) 
setX (x,y) x' = (x', y) 
setY (x,y) y' = (x, y') 
appX (x,y) f = (f x, y) 
appY (x,y) f = (x, f y) 
app2X (x, y) f = (f x y, y) 
app2Y (x, y) f = (x, f x y) 

set...設置一個值,app...在其上應用一個函數,app2...上在x或y的兩個值,並將其存儲應用一個函數。然後,你可以這樣做:

(vars 3 5) `setX` 14 `appY` (2*) 
-- result: (14,10) 

你的榜樣將成爲:

(vars 1 2) `app2X` (*) `app2Y` (+) 
-- result: (2,4) 

當然,這綿延「可變」一點的定義,但這種解決方案已經是一半對StateWriter monad。

1

另一種方法是考慮變量的「版本」 - 開始處的x與結尾處的x不同。例如,在C說你有,有時在華氏存儲號,然後將其轉換爲攝氏度,像這樣的變量:

 
    temp = 40; 
    temp = convertFtoC(temp); 

那麼你可以想想這些是兩個不同的變量:

 
    tempF = 40; 
    tempC= convertFtoC(tempF); 

不知道你的x和y,以創造更好地爲他們的名字,你可能最終在Haskell寫作:

 
xa = 1; 
ya = 2; 
xb = xa * ya; 
yb = ya + xb; 

在某些情況下,可以考慮如何的好方法使您的代碼更加實用,而且不太必要。