【问题标题】:Translate C code into Haskell将 C 代码翻译成 Haskell
【发布时间】:2011-09-05 17:53:09
【问题描述】:

如何将这部分 C 代码翻译成 Haskell?据我所知,我必须使用 State monad,但我不知道如何使用。

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

【问题讨论】:

  • 我只是想修改变量的值。
  • 如果你有更多的上下文会有所帮助。为什么要重新分配 x 和 y?在您的代码中,您根本不需要这样做,所以......当有人认为翻译只是 x = 2; y = 4 时,很难翻译它
  • 如果你想使用一种允许重新分配变量的语言,也许 Haskell 不是一个好的选择。如果您想以 Haskellish 方式学习 Haskell 编程,那么也许您应该重新考虑如何设计代码以完成您想要做的事情。
  • 这只是一个例子。我不能在这里发布代码。我必须执行某事。模拟 setter/getter 的行为。
  • @Bigba 为什么你不能?至少有一个最小的示例来解释为什么需要此功能可能会很有用。如果这是作业,请添加标签[作业]。

标签: c haskell translate


【解决方案1】:

直译会使用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

【讨论】:

    【解决方案2】:

    假设,你有这对整数作为状态:

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

    这是你想要的吗?

    【讨论】:

    • Google 上关于“set and get in haskell”查询的第一个结果将我带到haskell.org/haskellwiki/State_Monad。我猜翻译后的代码看起来像是那里给出的具体示例之一。
    • 请注意,这与 C 版本略有不同,因为在 C 代码中 x 被修改 之前 y 被设置,而不是同时设置,所以你可能需要 @987654323 @
    【解决方案3】:

    另一种方法是考虑变量的“版本” - 开头的 x 与结尾的 x 不同。例如,在 C 语言中,假设您有一个变量,它有时会以华氏度存储一个数字,然后将其转换为摄氏度,如下所示:

    温度 = 40; temp = convertFtoC(temp);

    那么您可以将它们视为两个不同的变量:

    温度 = 40; tempC=convertFtoC(tempF);

    在不知道你的 x 和 y 是什么来为它们发明更好的名字的情况下,你可能最终会在 haskell 中编写代码:

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

    在某些情况下,这可能是一种很好的方式来思考如何使您的代码更具功能性和更少的命令性。

    【讨论】:

      【解决方案4】:

      如果您使用元组标识“可变”变量,则可以在其上定义转换操作并将其“链接”在一起:

      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)
      

      当然,这有点延伸了“可变”的定义,但这个解决方案已经是 StateWriter monad 的一半了。

      【讨论】:

        【解决方案5】:

        函数式语言的要点是不要这样做、创建新值或使用递归。

        如果您只想打印这些值,

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

        如果这是家庭作业,请将其标记为,我会更改答案。

        【讨论】:

        • 这确实是一个家庭作业。更准确地说,是其中的一部分。我必须用 Haskell 翻译用 C 实现的电话簿。我只是想看看如何进行设置/获取操作。
        • @Bigba Mbum 你可能不需要它们。在 Haskell 中,很少使用 set 和 get 操作。其中大部分可以用纯粹的方式定义。
        • get and set 是一件非常必要的事情,除非你的老师知道你住在哪里并且喝了过多的伏特加并且看恐怖片,否则我不会使用它。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-05-12
        • 2016-08-04
        • 2014-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多