Перевести код на C на Haskell - PullRequest
1 голос
/ 31 мая 2011

Как мне перевести эту часть кода C на Haskell?Из того, что я знаю, я должен использовать Государственную монаду, но я не знаю как.

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

Ответы [ 5 ]

9 голосов
/ 31 мая 2011

Предположим, у вас есть пара целых чисел в качестве состояния:

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

Это то, что вы хотите?

8 голосов
/ 01 июня 2011

В буквальном переводе будет использоваться 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
6 голосов
/ 31 мая 2011

Смысл функциональных языков в том, чтобы вы не делали этого, не создавали новое значение или не использовали рекурсию.

Если вы хотите просто напечатать эти значения,

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

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

Если это домашнее задание, отметьте его, и я изменю свой ответ.

2 голосов
/ 01 июня 2011

Другой способ - подумать о «версиях» переменной - х в начале отличается от х в конце.Например, в C, скажем, у вас есть переменная, которая иногда хранит число в градусах Фаренгейта, а затем вы преобразуете его в градусы Цельсия, например:

  temp = 40;
  temp = convertFtoC(temp);

, тогда вы можете думать об этом как о двух разных переменных:

   tempF = 40;
   tempC=  convertFtoC(tempF);

Не зная, каковы ваши x и y, чтобы придумать для них лучшие имена, вы можете написать на haskell:

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

В некоторых случаях это может быть хорошим способомподумайте, как сделать ваш код более функциональным и менее обязательным.

1 голос
/ 01 июня 2011

Если вы идентифицируете свои «изменяемые» переменные с помощью кортежа, вы можете определить операции преобразования для него и «связать» его вместе:

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 монаду.

...