Ошибка Haskell: не удалось вывести (уравнение а), возникающее из буквального «0».

Я использовал код, представленный внизу этого документа: http://www.cs.dartmouth.edu/~doug/pearl.ps.gz

import Data.Ratio
infixl 7 .*
default (Integer, Rational, Double)

    -- constant series
ps0, x:: Num a => [a]
ps0 = 0 : ps0
x = 0 : 1 : ps0

    -- arithmetic
(.*):: Num a => a->[a]->[a]
c .* (f:fs) = c*f : c.*fs

instance Num a => Num [a] where
    negate (f:fs) = (negate f) : (negate fs)
    (f:fs) + (g:gs) = f+g : fs+gs
    (f:fs) * (g:gs) = f*g : (f.*gs + fs*(g:gs))
    fromInteger c = fromInteger c : ps0

instance Fractional a => Fractional [a] where
    recip fs = 1/fs
    (0:fs) / (0:gs) = fs/gs
    (f:fs) / (g:gs) = let q = f/g in
        q : (fs - q.*gs)/(g:gs)

    -- functional composition
compose:: Num a => [a]->[a]->[a]
compose (f:fs) (0:gs) = f : gs*(compose fs (0:gs))

revert::Fractional a => [a]->[a]
revert (0:fs) = rs where
    rs = 0 : 1/(compose fs rs)

    -- calculus
deriv:: Num a => [a]->[a]
deriv (f:fs) = (deriv1 fs 1) where
    deriv1 (g:gs) n = n*g : (deriv1 gs (n+1))

integral:: Fractional a => [a]->[a]
integral fs = 0 : (int1 fs 1) where
    int1 (g:gs) n = g/n : (int1 gs (n+1))

expx, cosx, sinx:: Fractional a => [a]
expx = 1 + (integral expx)
sinx = integral cosx
cosx = 1 - (integral sinx)

instance Fractional a => Floating [a] where
    sqrt (0:0:fs) = 0 : sqrt fs
    sqrt (1:fs) = qs where
        qs = 1 + integral((deriv (1:fs))/(2.*qs))

    -- tests
test1 = sinx - sqrt(1-cosx^2)
test2 = sinx/cosx - revert(integral(1/(1+x^2)))
iszero n fs = (take n fs) == (take n ps0)
main = (iszero 30 test1) && (iszero 30 test2)

При попытке запустить получаю следующие ошибки:

    Prelude> :load pearl.hs
[1 of 1] Compiling Main             ( pearl.hs, interpreted )

pearl.hs:22:10:
    Could not deduce (Eq a) arising from the literal ‘0’
    from the context (Num [a], Fractional a)
      bound by the instance declaration at pearl.hs:20:10-39
    Possible fix: add (Eq a) to the context of the instance declaration
    In the pattern: 0
    In the pattern: 0 : fs
    In an equation for ‘/’: (0 : fs) / (0 : gs) = fs / gs

pearl.hs:28:17:

    Could not deduce (Eq a) arising from the literal ‘0’
    from the context (Num a)
      bound by the type signature for
                 compose :: Num a => [a] -> [a] -> [a]
      at pearl.hs:27:11-32
    Possible fix:
      add (Eq a) to the context of
        the type signature for compose :: Num a => [a] -> [a] -> [a]
    In the pattern: 0
    In the pattern: 0 : gs
    In an equation for ‘compose’:
        compose (f : fs) (0 : gs) = f : gs * (compose fs (0 : gs))

pearl.hs:31:9:
    Could not deduce (Eq a) arising from the literal ‘0’
    from the context (Fractional a)
      bound by the type signature for
                 revert :: Fractional a => [a] -> [a]
      at pearl.hs:30:9-32
    Possible fix:
      add (Eq a) to the context of
        the type signature for revert :: Fractional a => [a] -> [a]
    In the pattern: 0
    In the pattern: 0 : fs
    In an equation for ‘revert’:
        revert (0 : fs)
          = rs
          where
              rs = 0 : 1 / (compose fs rs)

pearl.hs:49:15:
    Could not deduce (Eq a) arising from the literal ‘0’
    from the context (Fractional [a], Fractional a)
      bound by the instance declaration at pearl.hs:48:10-37
    Possible fix: add (Eq a) to the context of the instance declaration
    In the pattern: 0
    In the pattern: 0 : 0 : fs
    In an equation for ‘sqrt’: sqrt (0 : 0 : fs) = 0 : sqrt fs

pearl.hs:57:1:
    Couldn't match expected type ‘IO t0’ with actual type ‘Bool’
    In the expression: main
    When checking the type of the IO action ‘main’
Failed, modules loaded: none.

Я изменил «Коэффициент импорта» на «Коэффициент импорта Data.Ratio», но потом застрял.


person user2340939    schedule 19.10.2014    source источник


Ответы (1)


Сообщения GHC о «возможном исправлении» часто вводят в заблуждение, но это точно. Почему ты не попробовал?

Возможное исправление: добавьте (Eq a) в контекст объявления экземпляра.

i.e.

instance (Fractional a, Eq a) => Fractional [a] where
  ...

Это необходимо, потому что некоторые экземпляры Num могут не допускать сравнения на равенство (на самом деле этот экземпляр является отличным примером, поскольку бесконечные списки никогда не могут быть доказаны равными за конечное время!), но при написании шаблона (0:fs) / (0:gs) -> ..., вам нужна проверка на равенство, чтобы подтвердить, что голова на самом деле равна нулю. У списков, конечно, есть экземпляр Eq, но на самом деле это не общие списки, с которыми вы имеете дело, а всегда бесконечные списки (иначе эти шаблоны неисчерпаемы), поэтому вам следует использовать оболочку нового типа без экземпляра Eq, например

newtype Series a = Series {getSeries :: [a]}

В былые времена Eq был надклассом Num, чтобы [a] компилировалось без нареканий. Но, как я уже сказал, это было не очень хорошо.

person leftaroundabout    schedule 19.10.2014
comment
Я пробую что-то подобное, но теперь повезло, извините, я новичок. Но ваше предложение работает. Я исправил последнюю ошибку так: main::IO() main = print $(iszero 30 test1) && (iszero 30 test2) Это правильно? - person user2340939; 20.10.2014
comment
Выглядит неплохо. Если это не сработает, это проблема, совершенно не связанная с вашим первоначальным вопросом, опубликуйте еще один, если вы не можете это исправить. - person leftaroundabout; 20.10.2014