简体   繁体   中英

Haskell Error - No instance for (Num a) arising from the literal ‘1’

I am trying to create a function which adds a 1 before each of the entries in a given list. I haven't quite grasped the syntax for Haskell and am wondering what is wrong with this code. For example, I would like this to return the list [1,1,1,2,1,3]

ins1 :: [a] -> [a]
ins1 [x] = [x]
ins1 (x:xs) = [1] ++ [x] ++ ins1(xs)

main = print(ins1 [1,2,3])

I get the error:

• No instance for (Num a) arising from the literal ‘1’
  Possible fix:
    add (Num a) to the context of
      the type signature for:
        ins1 :: [a] -> [a]
• In the expression: 1
  In the first argument of ‘(++)’, namely ‘[1]’
  In the expression: [1] ++ [x] ++ ins1 (xs)
<interactive>:3:1: error:
• Variable not in scope: main
• Perhaps you meant ‘min’ (imported from Prelude)

Well like the error says, you use ins1 , and you write [1] ++ [x] ++ ... .

Now 1 is a numerical literal, so it can take all numerical types . Hence 1 has type Num b => b , as a result [1] has type Num b => [b] .

Later you append the list with x and recursion, hence we now know that a ~ b ( a and b are the same type). So we have to add a type constraint to the signature for a :

ins1 ::  [a] -> [a]
ins1 [x] = [x]
ins1 (x:xs) = [1] ++ [x] ++ ins1(xs)

This solves the compile error, but probably will not generate what you want. Since now there is no case for the empty list. Indeed, both the [x] pattern and the (x:xs) pattern work with lists that respectively match with lists with exactly one element, and at least one element.

Therefore I think that your first clause should actually match the empty list:

ins1 :: Num a => [a] -> [a]

ins1 (x:xs) = [1] ++ [x] ++ ins1(xs)

There is also an inefficiency in the second clause: you append to a list of one element, so we can use the " cons " data cosntructor (:) here:

ins1 :: Num a => [a] -> [a]
ins1 [] = []
ins1 (x:xs) = 

This will insert a 1 for every element in the original list, so:

Prelude> ins1 [1, 4, 2, 5]
[1,1,1,4,1,2,1,5]

If you give me a function of type [a] -> [a] , you're saying that, for all types a that I choose, if I give you a list of values of type a , then you can give me back a list of elements of that type.

So if I choose a to be Int by giving you [2, 3, 4] :: [Int] , then all is well: the literal 1 in the implementation of ins1 is constrained from Num t => t by t = Int to Num Int => Int . That works because there is an instance Num Int .

However, if I choose a to be Char , by giving you ['a', 'b', 'c'] (= "abc" ), then t = Char , giving Num Char => Char , which is an error because there's no instance Num Char . Therefore, this is a counterexample for the type: your function doesn't work for all a , only those a that have an instance of Num . So you need to express this constraint in the type signature:

ins1 :: (Num a) => [a] -> [a]

The compiler can infer this for you, and will display a warning about a missing type signature if -Wall is enabled (or -Wmissing-signatures specifically). This will also warn about the fact that ins1 is non-exhaustive : you don't handle the case of an empty input list. Alternatively, you can enter the definition into GHCi and ask for its type with :type ins1 or :t ins1 .

Generic functions in Haskell are parametrically polymorphic , which means that if you have an unconstrained type variable like a , you know nothing about it, not even that it can be constructed from a number literal. So the only things a function of type [a] -> [a] can do are copy, rearrange, or drop elements from the input, or fail to terminate (loop infinitely or raise an error)—it can't construct new elements or perform any class-specific operations on those elements, such as + from Num or < from Ord .

This may sound limiting, but in fact it's incredibly useful: the less you know about a type, the fewer options you have for misusing it. And by a neat trick called the Curry–Howard correspondence, you can examine a polymorphic function type like head :: [a] -> a and think of it as a logical formula: does having a list of a imply you can get an a ? No, because the list may be empty. So you know that a head function with this type must raise an error if the input is empty, because it has no generic way to construct an a .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM