Помогите мне понять эту ошибку типа Haskell (GHCI): (Num [Char]) при добавлении числа к строке - PullRequest
3 голосов
/ 06 июня 2011

Я делаю свою ежегодную попытку выучить Haskell в эти выходные, и, как и всегда, когда я пытаюсь написать рекурсивную функцию (а не просто набрать одну из учебника), я получаю ошибку типа.

Я бы очень признателен за любую помощь в понимании (1), что означает ошибка (я не понимаю "исправить"); и (2) почему вообще возникает ошибка - я совершенно уверен, что не делаю ошибок в отношении передаваемых типов.

Мой код:

tell :: (Show a) => [a] -> String  
tell'in :: (Show a, Num n) => [a] -> n -> String -> (n, String)
tell [] = "The list is empty"  
tell (x:[]) = "The list has one element: " ++ show x  
tell (x:xs) = "The list has " ++ n ++ " elements: " ++ s where (n, s) = (tell'in (xs) (1) (show x))  


tell'in (x:[]) n s = ((n + 1), (s ++ " and " ++ (show x)))
tell'in (x:xs) n s = tell'in xs (n+1)  (s ++ " and " ++ show x)

И ошибка, которую я получаю, когда пытаюсь загрузить это в GHCI:

[1 of 1] Compiling Main             ( example.hs, interpreted )

example.hs:13:88:
    Could not deduce (Num [Char]) arising from the literal `1'
    from the context (Show a)
      bound by the type signature for tell :: Show a => [a] -> String
      at example.hs:(11,1)-(13,99)
    Possible fix:
      add (Num [Char]) to the context of
        the type signature for tell :: Show a => [a] -> String
      or add an instance declaration for (Num [Char])
    In the second argument of `tell'in', namely `(1)'
    In the expression: (tell'in (xs) (1) (show x))
    In a pattern binding: (n, s) = (tell'in (xs) (1) (show x))
Failed, modules loaded: none.
Prelude>

Ответы [ 3 ]

3 голосов
/ 06 июня 2011

tell'in возвращает Num n => n, который вы затем (++) делаете с String (он же [Char]) в последнем уравнении для tell.Вы, вероятно, хотите использовать show n вместо n.

2 голосов
/ 06 июня 2011

Тип tell'in говорит, что первая координата его возвращаемого значения будет того же типа, что и его второй аргумент.В tell вы вызываете tell'in с номером в качестве второго аргумента (1), а затем используете первую координату возвращаемого значения (n) в качестве строки, добавляя ее к другим строкам.Таким образом, каким бы ни был этот тип, он должен быть одновременно строкой и числом.Ошибка говорит вам, что нельзя считать строку ([Char]) своего рода числом, которое возникает, когда она пытается интерпретировать значение числового литерала 1.Вы, вероятно, имели в виду

"The list has " ++ show n ++ " elements: " ++ ...
1 голос
/ 07 июня 2011

Существует общая схема для понимания ошибки компиляции, если это некое несоответствие типов: Вам нужно предоставить более конкретные аннотации типов, чтобы уменьшить ошибку!

tell'in и tell уже имеют типы:

tell :: (Show a) => [a] -> String  
tell'in :: (Show a, Num n) => [a] -> n -> String -> (n, String)

Итак, вы измените это:

tell (x:xs) = "The list has " ++ n ++ " elements: " ++ s
    where (n, s) = tell'in (xs) (1) (show x)) 

К этому:

--   vvvvvvvvvvvvvvvvvvvvvvv                      vvvvvvvv
tell ((x:xs)::(Show a=>[a])) = "The list has " ++ (n::Int) ++ " elements: " ++ s
    where (n::Int, s::String) = tell'in (xs) (1::Int) (show x)) 
--        ^^^^^^^^^^^^^^^^^^^^               ^^^^^^^^

Теперь либо вы уже видите ошибку, либо пытаетесь снова скомпилировать и получить более конкретное сообщение об ошибке.


В любом случае, лучше использовать ::Int вместо ::Num n=>n, поскольку последний будет обобщаться до ::Integer всякий раз, когда точный тип не указан. Int не больше, чем одно машинное слово (32/64 бита), и поэтому оно быстрее, чем Integer.

произвольного размера.
...