我刚刚尝试在Haskell中重写一些代码,本来是一个简短的Javascript函数。原始的有2个嵌套循环,内部循环包含两个循环计数器的相等性检查:
function f(x, points){
var i, j;
var n = points.length;
var result = 0;
for(i=0; i<n; i++){
var xprod = 1;
for(j=0; j<n; j++){
if(j != i){
xprod *= (x - points[j][0]);
}
}
result += points[i][1] * xprod;
}
return result;
}
Run Code Online (Sandbox Code Playgroud)
我希望能够在Haskell中对其进行简化,但是我无法弄清楚如何不有效地递归写出原始步骤的每一步而掌握i和j值。在Javascript中,Array.map将列表位置作为第二个参数传递到回调函数中,但是似乎Haskell中的map不会执行此操作。我要传递两个数组副本(每个循环一个),所以我当前的Haskell版本看起来很糟糕:
xproduct :: Int -> Int -> Double -> [(Double,Double)] -> Double
xproduct _ _ _ [] = 1
xproduct i j x (pt:todo)
| i == j = (xproduct i (j+1) x todo)
| otherwise = (xproduct i (j+1) x todo) * (x - (fst pt))
solvestep :: Int -> Double -> [(Double,Double)] -> [(Double,Double)] -> Double
solvestep _ _ _ [] = 0
solvestep i x pts (pt:todo) = ((snd pt) * xprod) + (solvestep (i+1) x pts todo)
where xprod = xproduct i 0 x pts
solve :: Double -> [(Double,Double)] -> Double
solve x points = solvestep 0 x points points
Run Code Online (Sandbox Code Playgroud)
有一个更好的方法吗?
我通常尽可能避免使用任何索引。在这种情况下,您真正使用的是:列表中的任何一个元素以及所有其他元素。无需使用索引比较来表达这一点,而是编写一个函数,该函数将使您在列表中有一个合适的外观:
pickouts :: [a] -> [(a,[a])]
pickouts [] = []
pickouts (x:xs) = (x,xs) : (second (x:) <$> pickouts xs)Run Code Online (Sandbox Code Playgroud)
然后,实际计算变为
f :: Double -> [(Double,Double)] -> Double
f x points = sum [q * product [x-p | (p,_)<-ps] | ((_,q),ps) <- pickouts points]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
77 次 |
| 最近记录: |