arrays - 在警戒条件下使用 unsafePerformIO
问题描述
我有这样的功能:
jac :: Int -> Int -> [Int] -> [Int] -> IOArray (Int,Int) Double -> IO Double
jac m k mu nu arr
| nu!!0 == 0 = return 1
| length nu > m && nu!!m > 0 = return 0
| m == 1 = return $ x!!0^(nu!!0) * theproduct (nu!!0)
| k == 0 && CONDITION = XXX
| otherwise = YYY
必须检查数组的CONDITION
那个元素是否不同于 0。但是要获得这个元素,必须做(1,1)
arr
element <- readArray arr (1,1)
我不明白该怎么做。除了unsafePerformIO
. 在这里使用它安全吗?我是说:
| k == 0 && unsafePerformIO (readArray arr (1,1)) /= 0 = XXX
不然我怎么办?
解决方案
让我们为您的问题制作一个简化版本。
假设我们要创建以下功能。它告诉我们这两个Int
值是否等于0
。问题是,它包含一个IO
. 您当前的方法是这样的:
-- THIS IS BAD CODE! This could easily cause unexpected behaviour.
areBothZero :: Int -> IO Int -> IO Bool
areBothZero a b
| a == 0 && unsafePerformIO b == 0 = return True
| otherwise = return False
这表明对单子的误解。在 Haskell 中,unsafePerformIO
作为一般规则不应该使用,除非你想达到纯计算无法达到的某种效果。然而,这种情况使用 monad 操作是完全可以实现的,与 不同的是,它是unsafePerformIO
完全安全的。
这就是我们实现这一目标的方式。首先,在 的上下文之外编写逻辑IO
:
areBothZeroLogic :: Int -> Int -> Bool
areBothZeroLogic a b
| a == 0 && b == 0 = True
| otherwise = False
然后,我们将其传递到IO
我们想要的逻辑:
areBothZeroIO :: Int -> IO Int -> IO Bool
areBothZeroIO a mb = do
b <- mb -- Use do-notation to work with the value 'inside' the IO:
return $ areBothZeroLogic a b
立即,这将IO
逻辑与纯逻辑分开。这是 Haskell 中的基本设计原则,您应该始终尝试遵循。
现在,到你的问题上。
您的问题更加混乱,并且还有其他几个问题,这向我表明您尚未考虑如何最好地将问题分解为更小的部分。然而,一个更好的解决方案可能看起来像这样,也许有更好的名字:
-- Look here! vvvvvv vvvvvv
jacPure :: Int -> Int -> [Int] -> [Int] -> Double -> Double
jacPure m k mu nu arrVal
| nu!!0 == 0 = 1
| length nu > m && nu!!m > 0 = 0
| m == 1 = x!!0^(nu!!0) * theproduct (nu!!0)
| k == 0 && arrVal /= 0 = XXX
| otherwise = YYY
jac :: Int -> Int -> [Int] -> [Int] -> IOArray (Int,Int) Double -> IO Double
jac m k mu nu arr = do
arrVal <- readArray arr (1,1) -- Use do-notation to work with the value 'inside' the IO:
return $ jacPure m k mu nu arrVal
您应该立即明白为什么这要好得多。在实现逻辑时,谁在乎IO
领域中发生了什么?在应该是纯逻辑的内容中包含一个IO
就像告诉作者他们的书将要印刷的纸张的酸度一样——这与他们的工作无关。总是分开逻辑和IO
!
当然还有其他方法可以做到这一点,有些方法很可能比我建议的方法更好。但是,不可能通过您提供的代码知道最佳路径。您应该致力于更多地了解 monad 并更好地使用它们,这样您就可以自己做出这个判断。
我怀疑这个问题是由于对 Monads 和 monadic 操作缺乏了解。如果您是初学者,我建议您阅读相关的 LYAH 章节,我发现它对初学者也很有帮助。
推荐阅读
- ios - 如何在 iOS (Ionic 2/3) 中下载文件?
- postgresql - psql 替代 SQL*Plus 格式化选项
- c# - 从串口读取 C#
- laravel - laravel 使用 like 运算符和百分比不起作用
- php - 如何设置pdf的标题名称。查看文档时(新标签)
- javascript - 在业力中使用 ES6 时出错
- javascript - 在反应 js 中将 Epoch 转换为 js 日期对象/时刻日期对象,不包括时区
- vb.net - Telerik ListView 项目更改高度
- c# - Python到C# Zlib解压转换
- python - 无法更新函数中使用的全局变量(Python)