2016-12-20 4 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] 

Я очень расстраиваюсь, поскольку система типов в Haskell на самом деле не такая интуитивная. Может ли кто-нибудь предложить лучшую практику при работе с плавающими числами в числовом вычислении?


Таким образом, приведенный выше код не работает, потому что:

  • В объявлении типа 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] 
Смежные вопросы