访问Haskell中诸如map之类的函数内部的列表位置

Ult*_*ent 1 haskell

我刚刚尝试在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)

有一个更好的方法吗?

lef*_*out 7

我通常尽可能避免使用任何索引。在这种情况下,您真正​​使用的是:列表中的任何一个元素以及所有其他元素。无需使用索引比较来表达这一点,而是编写一个函数,该函数将使您在列表中有一个合适的外观:

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)