#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
.