I don't want to spoil everything, but here are a few hints:
String is actually just another name for [Char].
- You can construct a new list that's just like an old one, but with a new element tacked onto the front with the
(:) :: a -> [a] -> [a] function (and in particular, (:) :: Char -> String -> String). You can read this function aloud as "cons". For example, 1:[2,3,4] is the same as [1,2,3,4], and 'a':"bcd" is the same as "abcd".
- When you're certain a list isn't empty, you can ask for its first element with the
head :: [a] -> a function (and in particular, head :: String -> Char).
- As an alternative strategy, you might want to look into pattern matching instead of using
null and if/then/else; this also eliminates the need for head, which is often a code smell.
From a comment, you've also tried something like this as your last line:
return head(lines) : []
The main problem here is that return is not a keyword in Haskell, it's just a plain old function. So if your argument is an expression, you need to parenthesize it (or use one of the various tricks for avoiding parentheses):
return (head(lines) : [])
return (head lines : [])
return $ head lines : []
return [head lines]
let answer = head lines : [] in return answer
etc. This should get you to where things typecheck and run; then you can get started correcting the bugs in the behavior of the code. =)