Перевести C-код на Haskell

#c #haskell #translate

#c #haskell #перевести

Вопрос:

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

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

Комментарии:

1. Я просто хочу изменить значение переменных.

2. Было бы полезно, если бы у вас было больше контекста. Почему вы хотите переназначить x и y? В вашем коде вам вообще не нужно этого делать, так что … это сложно перевести, когда можно утверждать, что перевод просто x = 2; y = 4

3. Если вы хотите использовать язык, который позволяет переназначать переменные, возможно, Haskell не является хорошим выбором. Если вы хотите научиться программировать на Haskell по-хаскеловски, то, возможно, вам следует пересмотреть то, как вы разрабатываете свой код, чтобы выполнить то, что вы пытаетесь сделать.

4. Это всего лишь пример. Я не могу опубликовать код здесь. Я должен реализовать sth. для имитации поведения установщика / получателя.

5. @Bigba Почему ты не можешь? Может быть полезно иметь хотя бы минимальный пример, объясняющий, зачем вам нужна эта функциональность. Если это домашнее задание, пожалуйста, добавьте тег [домашнее задание].

Ответ №1:

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

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

Это то, чего ты хочешь?

Комментарии:

1. Первый результат в Google по запросу «установить и получить в haskell» приводит меня к haskell.org/haskellwiki/State_Monad . Я предполагаю, что переведенный код будет выглядеть как один из конкретных примеров, приведенных там.

2. обратите внимание, что это немного отличается от версии C тем, что в коде C x изменяется перед установкой y, а не одновременно, поэтому вам, вероятно, понадобится put (1,2) >>= modify ((x,y) -> (x*y,y)) >>= modify ((x,y) -> (x,y x))

Ответ №2:

При буквальном переводе использовались бы 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
  

Ответ №3:

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

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

 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.

2. @Bigba Mbum Они тебе, наверное, не нужны. В Haskell операции set и get используются крайне редко. Большая часть этого может быть определена чистыми способами.

3. получение и установка — это очень важная вещь, я бы не стал ее использовать, если только ваш учитель не знает, где вы живете, не пьет чрезмерное количество водки и не смотрит фильмы ужасов.

Ответ №4:

другой способ — подумать о «версиях» переменной — 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;

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

Ответ №5:

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

 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 .