I am quite new in Haskell world. I was reading the online http://learnyouahaskell.com but I could not understand a small detail about pattern-matching section. I have written those functions
myFunc' (firstLetter:_) = firstLetter -- returns firstLetter of given string
However if I do something like that
myFunc' (firstLetter:_) = "Hello" ++firstLetter
Gives me following error when I call this function
Couldn't match type ‘Char’ with ‘[Char]’
Expected type: [[Char]]
Actual type: [Char]
But if I modify the function like this
myFunc' (firstLetter:_) = "Hello" ++ [firstLetter]
That works fine when I call this function. I was wondering why do I need brackets in other cases. What is actually firstLetter.
First, if you check the type of (++) in ghci, you get:
Prelude> :t (++)
(++) :: [a] -> [a] -> [a]
That means it takes two lists of a's as arguments.
Likewise let's see what (:) does:
Prelude> :t (:)
(:) :: a -> [a] -> [a]
So the first argument of (:) need not be a list at all. If we fix a == Char we in fact get (:) :: Char -> String -> String.
We can define a function headStr (recall String == [Char]):
headStr :: String -> Char
headStr (x:_) = x
headStr _ = error "Empty string!"
Note that due to the type of (:) in this case x :: Char.
On the other hand if we try to define:
hello :: String -> String
hello (x:_) = "Hello" ++ x
hello _ = error "Empty string!"
it will not type check because in the non error case we get [Char] ++ Char. As ghci helpfully told us, the second argument to (++) must always be a list and in this case since the first argument is [Char] it must also be [Char].
As you noticed yourself, this can be fixed by wrapping x in a list:
hello' :: String -> String
hello' (x:_) = "Hello" ++ [x]
hello' _ = error "Empty string!"
and this works as expected.
"Hello ++ firstLetter
The types there are:
[Char] ++ Char
As you can see, that isn't possible. You can't add a Char to a [Char], they are different types!
But by doing
[firstLetter]
you are creating a list with 1 element, firstLetter. Because firstLetter is a Char, you'll get a list of Chars, i.e. the list is of type [Char].
Adding 2 lists of the same type is allowed, and that's why it works in the second case.
Related
This is what I have so far:
toStr :: (Num a) => [a] -> String
toStr (x:xs)
| length xs == 0 = []
| length xs > 0 = show x : toStr xs
I keep getting this error:
* Couldn't match type `Char' with `[Char]'
Expected type: [String]
Actual type: String
I don't understand why it is receiving a Char instead of a [Char]. Thanks in advance.
For help, the thing I am trying to do is convert a binary list [1, 0, 0, 1, 1, 0] to a list like this "100110".
Understanding the Problem
toStr :: (Num a) => [a] -> String
toStr (x:xs)
| length xs == 0 = []
| length xs > 0 = show x : toStr xs
^ ^ ^
This is a String | |
| This is a String
This is a function of type String -> [String] -> [String]
So you have:
show x which is a String
toStr xs which is a String
The function : which expects a String and [String].
That disagreement on toStr xs is a String but was expected, by : to be a list of Strings is the crux of the problem. You wanted to concatenate your strings together into a single string (show x ++ toStr xs).
Understanding the Next Problem*
Now you should have a few other issues. First, you have an Num a => a that you try to show. The function show is not part of Num but instead part of the Show class so change Num a => to Show a =>.
Finally, this code doesn't handle the empty list case very well:
toStr (x:xs)
| length xs == 0 = []
Noticing nothing comes after x this code will ignore the last value, x, and return the empty list. It doesn't handle the case where there is no "last element" and all you have is the empty list. To handle that try toStr [] = [].
Putting it Together
toStr :: (Show a) => [a] -> String
toStr [] = []
toStr (x:xs) = show x ++ toStr xs
with a result of:
> toStr [1,0,0,1,1]
"10011"
Idiomatic Code
The above is a fine result but manual primitive recursive functions aren't usually necessary when writing Haskell. Most operations are a type of map or fold over the data. In this case it is a mapping of the show function (notice how it is showing every element) and a fold of the ++ function - also known as string concatenation.
toStr2 xs = foldr (++) "" (map show xs)
-- > toStr2 [1,0,0,1,1]
-- "10011"
Even this can be further simplified. It is so common there exists a special function concatMap:
toStr3 xs = concatMap show xs
Which we can "eta reduce" (remove the outer most arguments of the function definition/application - think in terms of defining a function as another function and not the values it produced):
toStr4 = concatMap show
Alternatively, we could re-gain the original verb-age of fold and map. The concatMap function is just a specific type of fold + map that works over lists. There is a more general foldMap that works with any function that produces a monoid (and lists are one such structure, which means that so are Strings since they are lists of characters):
toStr5 = foldMap show
As mentioned by Sergey, the ':' operator cannot be used, because the expression "show x" returns a string not a single character.
This code below seems to do what you wanted:
toStr :: (Num a, Show a) => [a] -> String
toStr (x:xs)
| null xs = show x -- avoid using length because of cost
| not (null xs) = (show x) ++ (toStr xs)
toStr [] = ""
main = do
let ls1 = [ 13, 17, 19, 23 ]
let st1 = toStr ls1
let st2 = concatMap show ls1 -- as per melpomene's remark
putStrLn $ "st1 = " ++ st1
putStrLn $ "st2 = " ++ st2
As a side remark, Haskell programmers generally avoid to use the length function when they just want to know whether a list is empty or not. Things can get really ugly if you do that, because of our potentially unlimited lazy lists.
For example:
wordsToString ["all","for","one","and","one","for","all"]
"all for one and one for all"
My code works without a type declaration:
wordsToString [] = ""
wordsToString [word] = word
wordsToString (word:words) = word ++ ' ':(wordsToString words)
But when I do the type check,it shows that it is a list of Chars which seems wrong to me as I'm supposed to declare the input as a list of strings and get a string as the output:
*Main> :type wordsToString
wordsToString :: [[Char]] -> [Char]
I want to change the declaration to wordsToString::[(String)]->[String] but it won't work
I want to change the declaration to wordsToString::[(String)]->[String] but it won't work
No, you want to change the declaration to wordsToString :: [String] -> String. You aren't getting a list of strings out, just a single one.
The function is called concat:
concat :: Foldable t => t [a] -> [a]
concat xs = foldr (++) [] xs
In your case, you want to insert a whitespace between the characters. This function is called intercalate:
intercalate :: [a] -> [[a]] -> [a]
It's defined in terms of intersperse.
I learned before that when using Haskell's read function when reading numbers from Strings you need to specify the type of output, as:
read "2" :: Int
unless you do something like:
read "2" + 2
Haskell then knows you're trying to do addition, hence it must be a number.
However, one particular function caught my attention, because by looking at function i thought it would not compile, but it does, i don't know why.
This reverse polish notation calculator that implements addition, subtraction and multiplication:
solveRPN :: (Num a, Read a) => String -> a
solveRPN xs = head . foldl foldingFunction [] . words $ xs
where foldingFunction (x:y:ys) "*" = (x * y):ys
foldingFunction (x:y:ys) "+" = (x + y):ys
foldingFunction (x:y:ys) "-" = (y - x):ys
foldingFunction xs numberString = read numberString:xs
if you give it a string like "2 5 +" it will return 7.
last line of this code is what i can't understand. When you give this function "2 5 +" the first element in xs list will be "2" and accumulator at time is [], hence it will slip through first 3 patterns and last one will do its job, hence:
foldingFunction [] "2" = read "2":[]
So, my question is: How come read "2":[] dosen't crash? If I tried to execute this bit in console it would give parse error becasue read wouldn't know what that string should be, right? how come it's not (read "2" :: Int):[] or something?
So what you have to understand is that Haskell assigns all the types of functions at compile time, not run time. Also, that functions have only one type for all their patterns.
What this means is that it will decide that the type of the function is overall and use that decision in every case. Also, Haskell does rather heavy type inference (unlike most other languages), and so will sometimes determine the type of a function based on the type of something that might seem a bit far away from the original function call.
Let's look at your example:
solveRPN :: (Num a, Read a) => String -> a
solveRPN xs = head . foldl foldingFunction [] . words $ xs
where foldingFunction (x:y:ys) "*" = (x * y):ys
foldingFunction (x:y:ys) "+" = (x + y):ys
foldingFunction (x:y:ys) "-" = (y - x):ys
foldingFunction xs numberString = read numberString:xs
First off, the type of solveRPN is declared as String -> a.
Now, looking at the definition of solveRPN, we have the first line saying:
solveRPN xs = head . foldl foldingFunction [] . words $ xs
Now, the types of the names used there are:
xs :: String (from the type of solveRPN)
head :: [b] -> b (I'm using different variable names for each different type)
foldl :: (c -> d -> c) -> c -> [d] -> c
words :: String -> [String]
So the type of solveRPN means that we must have that type b is the same as type a, and since head is applied to the output of foldl, we must have that type c is the same as type [a]. Now since the third argument to foldl is of type [String], we know that type d is String, and now we have enough to determine the type of foldingFunction:
foldingFunction :: [a] -> String -> [a]
Let's work backwards.
head . foldl foldingFunction [] . words :: Num a => String -> a
foldl foldingFunction [] .words :: Num a => String -> [a]
foldl foldingFunction [] :: Num a => [String] -> [a]:
Since foldl ::Foldable t => (b -> a -> b) -> b -> t a -> b, we can see that t a ~ [String], so we can also see that foldingFunction :: Num a => [a] -> String -> [a].
Thus, read "2" : [] :: Num a => [a], the same type as foldingFunction [] "2".
In other words, solveRPN provides the necessary context to infer what read should return.
If I tried to execute this bit in console it would give parse error becasue read wouldn't know what that string should be, right?
(Thanks to haskell-cafe mailing list for help on this.)
You are getting a parse error at the GHCI REPL because in the absence of a type context, GHCi evaluates the expression as if it were the type () (the empty tuple type.)
For instance, this does not give an error:
GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help
Prelude> read "()"
()
This is a consequence of the -XExtendedDefaultRules option which is implicitly in effect when using GHCi. See Type defaulting in GHCi in the GHC User Guide for more details on why GHCi has these extended defaulting rules.
To see how this option affects evaluation, you can perform the same experiment with the option disabled:
GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help
Prelude> :set -XNoExtendedDefaultRules
Prelude> read "2"
<interactive>:3:1:
No instance for (Read a0) arising from a use of ‘it’
The type variable ‘a0’ is ambiguous
...
Now we get a No instance for ... error message. This is the message that tells you that GHC does not know which type to return.
The context (Num a, Read a) => on your solveRPN function are enough for read to figure it out. Try this in ghci:
let n = read "2" :: (Num a, Read a) => a
:t n
I want to write a replicate-like function that works like this :
repli "the" 3 = "ttthhheee" and
repli "jason" 4 = "jjjjaaaassssoooonnnn"
Here is the code that I wrote :
myrepli [] n = []
myrepli [x] 0 = []
myrepli [x] n = (x:(myrepli [x] (n-1)))
repli [] n = []
repli (x:xs) n = (myrepli x n) ++ (repli xs n)
The error I get is this :
Couldn't match expected type `[a]' against inferred type `Char'
Expected type: [[a]]
Inferred type: [Char]
In the first argument of `repli', namely `"jason"'
In the expression: repli "jason" 3
How can I fix this? Thanks.
For problems with types, here's a trick that has helped me immensely. Whenever I am completely baffled by a message like this, I do the following:
If there's a type signature on the function in question, remove it and see if anything changes. If it compiles, ask ghci what the type is (using :t). If it doesn't compile, at least the error message may differ enough to give you another clue.
If there's no type signature, add one. Even if it doesn't compile, the error message may give you another clue.
If that doesn't help, then temporarily add type declarations on each of the expressions in the function. (Often you'll need to break up some of the expressions to see what's really going on. You may also need to temporarily enable the ScopedTypeVariables pragma.) Compile again and check the error messages.
That last one is more work, but I've learned a lot from that exercise. It usually pinpoints the exact place where there's a mismatch between what I think the type is and what GHC thinks the type is.
So let's begin by adding type signatures to your code:
myrepli :: [a] -> Int -> [a]
myrepli [] n = []
myrepli [x] 0 = []
myrepli [x] n = (x:(myrepli [x] (n-1)))
repli :: [a] -> Int -> [a]
repli [] n = []
repli (x:xs) n = (myrepli x n) ++ (repli xs n) -- triggers a compiler error
Ah, now we get a compiler error:
amy.hs:9:27:
Couldn't match expected type `a' with actual type `[a]'
`a' is a rigid type variable bound by
the type signature for repli :: [a] -> Int -> [a] at amy.hs:7:10
In the first argument of `myrepli', namely `x'
In the first argument of `(++)', namely `(myrepli x n)'
In the expression: (myrepli x n) ++ (repli xs n)
The problem is in the call to myrepli x n. The function myrepli expects a list/string, but you're passing it a single character. Change that last line to:
repli (x:xs) n = (myrepli [x] n) ++ (repli xs n)
At that point you will find other errors in your code. But rather than fix your code, let me show you another way to do it:
repl (x:xs) n = (myReplicate x n) ++ (repl xs n)
repl [] _ = []
-- You could use the library function "replicate" here, but as a
-- learning exercise, we'll write our own.
myReplicate a n = take n (repeat a)
myrepli is expecting a list and an integer. However, the definition of repli calls it with x, which is an item, not a list of items.
I imagine you either want to change myrepli to take a single item as argument, or you want to change repli to pass [x] instead of just x. (I would suggest the former rather than the latter.)
I recently started learning Haskell and I'm trying to rewrite something I did for an interview in python in Haskell. I'm trying to convert a string from camel case to underscore separated ("myVariableName" -> "my_variable_name"), and also throw an error if the first character is upper case.
Here's what I have:
import qualified Data.Char as Char
translate_java :: String -> String
translate_java xs = translate_helper $ enumerate xs
where
translate_helper [] = []
translate_helper ((a, num):xs)
| num == 1 and Char.isUpper a = error "cannot start with upper"
| Char.isUpper a = '_' : Char.toLower a : translate_helper xs
| otherwise = a : translate_helper xs
enumerate :: (Num b, Enum b) => [a] -> [(a,b)]
enumerate xs = zip xs [1..]
I realize It's pretty likely I'm going about this in a weird way, and I'd love advice about better ways to implement this, but I'd like to get this to compile as well. Here's the error I'm getting now:
Prelude> :r
[1 of 1] Compiling Main ( translate.hs, interpreted )
translate.hs:4:20:
No instance for (Num
(([Bool] -> Bool) -> (Char -> Bool) -> Char -> t))
arising from a use of `translate_helper' at translate.hs:4:20-35
Possible fix:
add an instance declaration for
(Num (([Bool] -> Bool) -> (Char -> Bool) -> Char -> t))
In the first argument of `($)', namely `translate_helper'
In the expression: translate_helper $ enumerate xs
In the definition of `translate_java':
translate_java xs
= translate_helper $ enumerate xs
where
translate_helper [] = []
translate_helper ((a, num) : xs)
| num == 1 and Char.isUpper a
= error "cannot start with upper
"
| Char.isUpper a
= '_' : Char.toLower a : transla
te_helper xs
| otherwise = a : translate_help
er xs
Failed, modules loaded: none.
Any explanation of what's going on here would be great. I really don't understand where "(Num (([Bool] -> Bool) -> (Char -> Bool) -> Char -> t))" is coming from. I'd think the type declaration for translate_helper would be something like [(a,b)] -> [a]?
You have to replace and by &&. The first one is a function (prefix) that receives a list of boolean values and calculates an and of them all. The second one is a true logical and. The error message is a little bit confusing though. Whenever I get such a strange error message, I usually start to annotate my code with type signatures. Then the compiler is able to give you a more detailed description of what went wrong.
Others have mentioned that you should use (&&) instead of and, so I'll answer your other question: no, I don't think you're going about this in a weird way.
But... I do think it can be even more elegant!
translate_java (x:xs) | isUpper x = error "cannot start with an upper"
translate_java xs = concatMap translate xs where
translate x = ['_' | isUpper x] ++ [toLower x]
There's a few interesting things going on here:
The special case is checked straight away. Don't wait until you're recursing to do this!
The concatMap function is really handy in a lot of cases. It's just a map followed by a concat. If I were writing this myself, I'd probably use xs >>= translate instead.
That ['_' | isUpper x] is a list comprehension; this is a cute idiom for making a list with either 0 or 1 elements in it, depending on whether a predicate holds.
Other than that, the code should be fairly self-explanatory.
The problem is this:
| num == 1 and Char.isUpper a = ...
and is not an infix operator; rather it is a function:
and :: [Bool] -> Bool
So it is interpreting 1 and Char.isUpper a as applying three arguments to the "function" 1. Use && instead.
The error message comes from the way numerals are interpreted. A numeral, say, 1 is actually polymorphic; the specific type it gets depends on the type that is needed. That's why you can say x+1 and it will work whether x is an integer or a double or whatever. So the compiler inferred that the type of 1 needs to be a three-argument function, and then tried to find a numeric type matching that so it could convert 1 into that type (and, naturally, failed).
Here's my solution. It's not as masterful as the answer Daniel Wagner gave using concatMap and the list comprehension, but it's perhaps easier to understand for the beginner.
conv :: String -> String
conv [] = []
conv s#(x:xs) = if Char.isUpper x
then error "First character cannot be uppercase"
else change s
change :: String -> String
change [] = []
change (x:xs) = if Char.isUpper x
then '_' : Char.toLower x : change xs
else x : change xs
The function conv really just checks your criterion that the first character must not be uppercase, and if it isn't it hands over the string to the function change, which does the work. It goes through all the characters one by one, building a list, and if the character is uppercase, it adds an underscore followed by the lowercase version of the character, otherwise if the character is already lowercase it just adds it as it is.