Реализовать закон косинуса в Хаскеле? - PullRequest
0 голосов
/ 28 января 2019

Итак, я хочу создать свою собственную функцию косинуса, используя эту формулу: enter image description here

Функция должна возвращать значение, если его абсолютное значение больше 0,001.

Однако в моем коде, похоже, есть ошибки типа, которые я просто не знаю, как исправить.Я уже пытался изменить все типы на Double, но он все еще не работает.

fac :: Int -> Int
fac n = if (n == 0) then 1 else n * fac (n-1)

cos :: Double -> Double
cos x = sum [cos| k <- [0..],
                  let cos = (-1) * (x^(2*k) `div` fac (2*k)) , 
                  abs (cos) > 0.001]

Это ошибка:

• Не удалось сопоставить ожидаемый тип 'Double' сфактический тип 'Int'

• Во втором аргументе 'div', а именно: fac (2 * k) '

1 Ответ

0 голосов
/ 28 января 2019

Здесь в основном две проблемы:

  • div только для целочисленного деления (то есть принимает целочисленные входы и производит интегральный вывод только путем округления в меньшую сторону).Вы хотите (/) для деления с плавающей точкой.
  • fac возвращает Int, которое вы должны явно преобразовать в число с плавающей точкой перед использованием в делении.(Многие языки автоматически преобразуют целочисленные типы в типы с плавающей запятой, но Haskell этого не делает.) Для преобразования вы можете использовать fromIntegral.

Исправляя эти две вещи, но ничего больше мы не получим:

fac :: Int -> Int
fac n = if (n == 0) then 1 else n * fac (n-1)

cos :: Double -> Double
cos x = sum [cos| k <- [0..],
                  let cos = (-1) * (x^(2*k) / fromIntegral (fac (2*k))) , 
                  abs (cos) > 0.001]

Эта проверка типов, хотя и имеет несколько других проблем, от самых важных до минимальных:

  • Вы, вероятно, надеялись, что Хаскелл каким-то волшебным образом узнает, что однаждыabs cos <= 0.001 за одну итерацию, она останется такой же для всех будущих итераций и прекратит итерацию.Но это не так.Вы сказали рисовать k из [0..], и поэтому он вытянет k из всего этого списка - никогда не заканчивая.Вместо этого вам может понравиться takeWhile.
  • Вы потеряли показатель k на -1!
  • Даже если не учитывать, является ли эта формула наиболее эффективной для начала, ваша реализацияповторяет много работы.Каждый вызов fac (2*k) должен пересчитать все предыдущие факториалы, которые он сделал, в качестве промежуточных результатов;и ваш x^(2*k) повторяет какую-то работу (хотя и в гораздо меньшей степени).
  • Повторное использование имени cos довольно запутанно.Хотя технически это не делает программу неправильной , я бы ее избежал.

Я оставляю вам возможность повеселиться, изучая Haskell и учась самостоятельно решать эти проблемы.- Я думаю, что это хорошо в пределах способностей, которые вы показали здесь!

...