这是一个愚蠢的任务
将 C 直接翻译成 Haskell 是相当愚蠢的。我以前做过付费,但进展并不顺利或迅速。最好用目标语言以惯用的方式描述任务并实现它。通过提供算法的英文描述,您更有可能获得高质量的答案。
请发布可编译代码
当您发布问题时,请确保它可以编译!
学习 Haskell 而不是如何在 Haskell 中编写 C
不同语言的处理方式可能会有很大差异,尤其是当您跨越诸如从命令式到函数式,或从可变到不可变,或从严格到惰性,或隐式转换为显式或手动管理的内存到垃圾收集的鸿沟时。你正在跨越所有这些鸿沟。
如果您的任务是学习 Haskell,那么您的起点就错了。如果您的任务是在 Haskell 中学习可变向量/数组,那么您需要了解更多的基础知识以了解其中的细微差别。如果你的任务是嘲笑 Haskell 对数组的支持很差,那么在 Roman 出现并制作 Vector 包之前,你会很轻松地度过它——这就是我的说法:不要只看 HaskellArray
的外观在Vector
s。
好的好的,有什么解决办法?
我们将把Vector
包用于我们的数组,将ST
monad 用于可变操作(你的第一个要点):
import qualified Data.Vector.Unboxed.Mutable as M
import qualified Data.Vector.Unboxed as V
import Control.Monad.ST
import Control.Monad
您的 main 函数接受两个向量并返回一个浮点数。我们首先使用获取对数组的可变引用,thaw
并使用简单的折叠来允许我们翻转数组引用。
someFunc :: V.Vector Float -> V.Vector Float -> Float
someFunc arrA arrB = runST $ do
-- Obtain mutable copies of the arrays
mA <- V.thaw arrA
mB <- V.thaw arrB
(mA', mB') <- foldM op (mA, mB) [1..n-1] -- for(i = 1 ; i < n; i++)
M.read mA' 0
where
n = min (V.length arrA) (V.length arrB)
内部 for 循环包含在op
. 它只是从数组中执行一些简单的读取并写入一个新值。它必须在一个元组中返回两个数组;每次迭代都会翻转元组以获得可变指针的相同语义(您的第二点):
op (mA, mB) i = do
forM_ [0..n-i-1] $ \j -> do
v1 <- M.read mA j
v2 <- M.read mB (j+1)
M.write mB j (someFn i j v1 v2)
return (mB, mA)
与您的第三点一致,内循环边界会根据外循环而变化。
这样我们就可以编译一个可运行的程序,我们将包括 main:
someFn i j f1 f2 = f1 + fromIntegral i + fromIntegral j - f2
main = print $ someFunc (V.fromList [1..10]) (V.fromList [0..9])
这仅用于教育目的。我没有对此进行测试,它在道德上应该与您的 C 相同,但可能会在循环中偏离一个或有其他微不足道的差异。