如何将这部分 C 代码翻译成 Haskell?据我所知,我必须使用 State monad,但我不知道如何使用。
int x = 1;
int y = 2;
x = x * y;
y = y + x;
假设,你有这对整数作为状态:
f = do put (1,2)
modify (\(x,y) -> (x*y,y))
modify (\(x,y) -> (x,y+x))
那是你要的吗?
直译将使用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
函数式语言的重点是不要这样做,创建新值或使用递归。
如果您只想打印这些值,
x = 1
y = 2
a = x*y
b = y+x
main = do
putStrLn ("x*y: " ++ a)
putStrLn ("y+x: " ++ b)
如果这是家庭作业,请标记为,我会更改答案。
另一种方法是考虑变量的“版本”——开头的 x 与结尾的 x 不同。例如,在 C 语言中,假设您有一个变量,它有时会以华氏温度存储一个数字,然后将其转换为摄氏度,如下所示:
温度 = 40; temp = convertFtoC(temp);
那么您可以将它们视为两个不同的变量:
温度 = 40; tempC=convertFtoC(tempF);
在不知道你的 x 和 y 是什么来为它们发明更好的名字的情况下,你最终可能会在 haskell 中编写:
xa = 1; 雅 = 2; xb = xa * ya; yb = ya + xb;
在某些情况下,这可能是一种很好的方式来思考如何使您的代码更具功能性和更少的必要性。
如果您使用元组标识“可变”变量,则可以在其上定义转换操作并将其“链接”在一起:
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
or Writer
monad 的一半了。