如何将这部分C代码翻译成Haskell?据我所知,我必须使用State monad,但我不知道如何。
int x = 1;
int y = 2;
x = x * y;
y = y + x;
答案 0 :(得分:9)
让我们假设,你有一对整数作为状态:
f = do put (1,2)
modify (\(x,y) -> (x*y,y))
modify (\(x,y) -> (x,y+x))
那就是你想要的吗?
答案 1 :(得分:8)
字面翻译将使用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 :(得分:6)
函数式语言要点不要这样做,创建新值或使用递归。
如果您只想打印这些值,
x = 1
y = 2
a = x*y
b = y+x
main = do
putStrLn ("x*y: " ++ a)
putStrLn ("y+x: " ++ b)
如果这是家庭作业,请将其标记为,我将更改我的答案。
答案 3 :(得分:2)
另一种方法是考虑变量的“版本” - 开头的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;
在某些情况下,这可能是思考如何使代码更具功能性和更少命令性的好方法。
答案 4 :(得分: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)
当然这有点延伸了“可变”的定义,但这个解决方案已经到了State
或Writer
monad的一半。