2016-12-20 16 views
1

カーブの下の面積を計算する短い関数を書こうとしていますが、タイプミスマッチエラーが続いています。Haskell浮動小数点計算エラー

l,rは評価の範囲であり、aおよびbはカーブのパラメータです。

solve :: Int -> Int -> [Int] -> [Int] -> [Double] 
solve l r a b = [area] 
    where eval a b p = fromIntegral . sum . map (\(ai, bi) -> ai * p^bi) $ zip a b 
      area = foldl (\acc p -> acc + 0.001 * eval a b p) 0 range 
      range = map (\a -> (fromIntegral a :: Double)/1000) [l*1000..r*1000] 

ハスケルのタイプシステムが本当に直感的ではないので、私はかなり不満を感じています。数値計算で浮動小数点数を扱う際にベストプラクティスを提案する人はいますか?要約する


ため、上記のコードが機能しない:型宣言a

  • [Int]
  • として宣言され、したがってHaskellは(*)が持っているのでevalも、Int型を持つと推察署名Num a => a -> a -> a(同じタイプのパラメータのみをとるように)

入力タイプを変更せずにこの問題の代数曲線を浮動小数点値に評価する場合は、a[Double]にキャストするだけです。ここでは、コードです:

solve :: Int -> Int -> [Int] -> [Int] -> [Double] 
solve l r a b = [area] 
    where eval p = sum . map (\(ai, bi) -> ai * p ^^ bi) $ zip af b 
      area = foldl (\acc p -> acc + 0.001 * eval p) 0 range 
      range = map (\x -> (fromIntegral x :: Double)/1000) [l*1000..r*1000] 
      af = map fromIntegral a :: [Double] 

私も負の指数に対処する^^^を変更しました。

答えて

4

タイプエラーを理解するには、いくつかのタイプを調べる必要があります:)。開始するには、型宣言をコメントアウトしてGHCiの推論を見てください(この場合はエラーは変わりませんが、型宣言が問題ではないことを確認するのがよい一般的な方法です)。我々は、彼らが同じ型の引数を受け入れ、関連する数値演算子(*)(+)の型シグネチャから知っている

floatingError.hs:4:47: error: 
    • No instance for (Integral Double) arising from a use of ‘eval’ 
    • In the second argument of ‘(*)’, namely ‘eval a b p’ 
     In the second argument of ‘(+)’, namely ‘0.001 * eval a b p’ 
     In the expression: acc + 0.001 * eval a b p 

:我々はこれを行うときとにかく、我々は、エラーが発生しました。これが私たちの誤りの原因です。 evalは、一体型であると予想される。しかし、我々はそれにfromIntegral関数を適用しました。したがって、これを削除すると、関数のアプリケーション型チェックとプログラムがコンパイルされます。

次に、我々はGHCiのはsolveのために推測どのようなタイプの署名をチェックすることができます

solve :: (Integral b, Integral t) => 
t -> t -> [Double] -> [b] -> [Double] 

Intは型クラスIntegralのインスタンスを持っているので、私たちは私たちの宣言の署名は、当社の修正関数定義と矛盾しないことを知っています。


私たちの最終的なコード:

solve :: Int -> Int -> [Double] -> [Int] -> [Double] 
solve l r a b = [area] 
    where eval a b p = sum . map (\(ai, bi) -> ai * p^bi) $ zip a b 
     area = foldl (\acc p -> acc + 0.001 * eval a b p) 0 range 
     range = map (\a -> (fromIntegral a :: Double)/1000) [l*1000..r*1000]