C コードのこの部分を Haskell に変換するにはどうすればよいですか? 私が知っていることから、State モナドを使用する必要がありますが、方法がわかりません。
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))
それは、あなたが望むものですか?
直訳はIORefを使用します:
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)
これが宿題の場合は、そのようにマークしてください。答えを変更します。
もう 1 つの方法は、変数の「バージョン」について考えることです。最初の x は最後の x とは異なります。たとえば、C では、数値を華氏で格納する変数があり、次のように摂氏に変換するとします。
温度 = 40; temp = convertFtoC(temp);
次に、これらを 2 つの異なる変数と考えることができます。
tempF = 40; tempC= convertFtoC(tempF);
あなたの x と y が何であるかを知らずに、それらのより良い名前を考え出すと、haskell で書くことになるかもしれません:
xa = 1; ya = 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
orWriter
モナドへの道のりの半分です。