addOneTwo :: [String] -> [String]
addOneTwo [] = "1" : "2" : [x]
This says:
addOneTwo is a function that accepts a [String] and returns a [String]
When addOneTwo is called on an empty list, that is, addOneTwo [], it evaluates to a list where:
- The head is
"1"
- The tail is a list where:
- The head is
"2"
- The tail is a list of one element,
x (or, in other words, its head is x and its tail is [])
Since you don’t define a variable called x in this code, this is a scoping error. One way to fix this is the following:
Remove the pattern [] and replace it with the pattern x, that is, just a parameter name.
Since this parameter is a list, use it as the second operand of the cons operator (:) directly, that is, … : x instead of *… : [x]
addOneTwo :: [String] -> [String]
addOneTwo x = "1" : "2" : x
Conventionally, lists are often named with an s suffix, like xs or strings, so you could rename x too if you like.
To understand your original code in more depth, maybe it’ll be illuminating to go over how it would be desugared:
addOneTwo =
\ xs -> case xs of {
[] -> "1" : ("2" : (x : []));
_ -> error "Non-exhaustive patterns in function addOneTwo"
}
Since addOneTwo is a function, it can be defined using a function value, that is, a lambda expression. I’ve given the parameter of this function the name of xs. When you write the definition addOneTwo [] = …, the pattern addOneTwo [] means you’re defining the result of evaluating the expression addOneTwo []. The “equals” sign really does mean “equals”!
This is equivalent to taking a parameter and pattern-matching on it explicitly with a case expression. Notice that I included an error case, which is implicitly generated when you don’t cover all possible inputs—in this case, when addOneTwo is applied to a non-empty list, like addOneTwo [3]. GHC can warn you about such uncovered cases if you enable -Wincomplete-patterns; that’s implied by -Wall, which produces a variety of other helpful warnings.
Whereas, the corrected definition would desugar to the following:
addOneTwo =
\ x ->
"1" : ("2" : x)
Since all inputs will be matched by the pattern x, there is no need for an error alternative, or any case expression at all.
I want to program a function that takes a string-list and just adds "1" and "2" to it.
Well, there you go! But keep in mind: this isn’t adding elements to the same list in-place, it’s just making a list that shares some suffix with the old one. And that’s the normal way of representing incremental updates to a data structure in Haskell: a function f :: T -> T takes in a value representing one state and returns a value representing the modified state, and we rely on the garbage collector to reclaim parts of the old state that are no longer used.
f [] = ...means "if the input list is empty then the result is ...". Usually it's followed by another equation covering the non-empty case. I don't know why you use that in your code. Try insteadf xs = "1" : "2" : xs-- no need to distinguish between the empty/nonempty cases here.