2015-05-05 2 views
2

Я новичок в Haskell, и я пишу программу, которая вычисляет предел функции. Поэтому, учитывая два списка a и b, дельта dx = 0.001 и пределы интегрирования l и r, я хочу, чтобы рекурсивно вычислить площадь под кривой с уравнением: a1(x)^b1 + a2(x)^b2 + ... + an(x)bn где x это все значения между lr с приращением dx между каждым значением. Техническая часть не так важна, я думаю, но это помогает читать код:Нет экземпляра для (Fractional Int), возникающего из-за использования `area '

import Text.Printf (printf) 

-- This function should return a list [area]. 
solve :: Int -> Int -> [Int] -> [Int] -> [Double] 
solve l r x y = [area l r x y] 

area l r a b = if (l < r) 
      then (calc l a b) * 0.001 + (area (l + 1) r a b) 
      else (calc r a b) * 0.001 


calc n (a:arest) (b:brest) = (fromIntegral(n) ^^ b) * fromIntegral(a) + (calc n arest brest) 
calc n [] [] = 0 


--Input/Output. 
main :: IO() 

main = getContents >>= mapM_ (printf "%.1f\n"). (\[a, b, [l, r]] -> solve l r a b). map (map read. words). lines 

я не получаю сообщение об ошибке с указанным кодом, но как только я меняю area (l + 1) r a b к area (l + 0.001) r a b я получаю следующее сообщение об ошибке:

No instance for (Fractional Int) arising from a use of `area' 

Я пробовал сделать новый класс и иметь абстрактный тип, но это не сработало, никаких других идей?

+2

Try добавления сигнатуры типов для всех функций верхнего уровня. Это также поможет вам определить, какие аргументы должны быть целыми и какие из них должны быть удвоены, например. – chi

ответ

7

Таким образом, проблема заключается в том, что Int не является Fractional. Другими словами, он не имеет значения, называемого 0.001[примечание 1], но вы запросили у Haskell такую ​​ценность в своем коде.

Вы делаете этот запрос, потому что 0.001 подается в (+) функции с другим аргументом (в данном случае l), который имеет тип Int. Это проблема, потому что функция имеет тип (+) :: (Num a) => a -> a -> a: другими словами, существует множество различных функций (+) всех типов a -> a -> a; одна из этих функций существует для каждого типа a класса Num.

Поскольку мы знаем, что одним аргументом функции является Int, из этого следует, что мы используем определенную функцию (+) :: Int -> Int -> Int. Вот почему l + 0.001 странно.

Что касается решения проблемы: Вы, наверное, хотели l и r быть типа Double (они левые и правые границы на то, где число может быть?), Но если вы уверены, что они должны быть Int s тогда вы, вероятно, хотели написать fromIntegral l + 0.001.

Side замечания о стиле: круглые скобки в Haskell всегда просто группировка/приоритете функция более высокий приоритет, чем операторы, которые имеют более высокий приоритет, чем специальные формы (let, case, if, do), и применение функции всегда левоассоциативные или «жадный ном»: функция ест все, что непосредственно перед ней. То, что вы написали:

(fromIntegral(n) ^^ b) * fromIntegral(a) + (calc n arest brest) 

, вероятно, лучше записать в виде:

fromIntegral a * fromIntegral n ^^ b + calc n arest brest 

скобки вокруг calc не нужны (потому что операторы, такие как + имеют более низкий приоритет, чем функции приложений), равно как и круглые скобки вокруг n и a (поскольку эти подвыражения являются неделимыми кусками, fromIntegral(n) идентичен fromIntegral (n), идентичен fromIntegral n).

  1. Как @dfeuer упоминает ниже: тайно, когда вы пишете 0.001, он не имеет определенного типа; скорее он переводится в fromRational 0.001 внутри, где последний 0.001 является определенным значением определенного типа Rational, так же, как когда вы пишете 4, он переводится на fromInteger 4, где последний 4 является определенным значением определенного типа Integer. Проблема заключается в том, что на самом деле не существует fromRational функции Int, потому что Int не является частью Fractional класса типов, которая определяет fromRational. И это не часть этого класса, потому что разработчики языка предпочли ошибку для молчания округления/падения доли.
+0

Мне кажется, что «не имеет экземпляр для' 0.001'»немного сбивает с толку. Что действительно происходит, так это то, что буквальный '0,001' действительно означает' fromRational 0,001'. 'fromRational :: Fractional a => Rational -> a', следовательно, ошибка. – dfeuer

+0

@dfeuer Спасибо, отредактировал его, чтобы это отразить. –

Смежные вопросы