Haskell: Type Error in Explicitly Typed Binding - haskell

I'm trying to create a function that will remove all occurrences of a given character in a string, but being the Haskell amateur that I am, I've run into issues that are making it hard to sleep.
Here's my code:
remove:: Char -> String -> Int
remove[] = []
remove (char : list) = char : remove (filter (\elm -> not (char == elm) ) list)
With the type definitions in, I get the following error code:
ERROR "a5.hs":17 - Type error in explicitly typed binding
*** Term : char : list
*** Type : [a]
*** Does not match : Char
Can anyone please help?

The type signature says that remove takes two parameters, a Char and a String, and gives back an Int.
The error message refers to the second equation, which tries to match the first parameter (a Char) to (char : list) (a list).
Perhaps you meant
remove char list = ...
?
Further errors:
The first equation makes the same mistake (trying to match an empty list with the Char parameter).
Perhaps this should be
remove _ [] = ...
(_ means to match anything.)
The type signature says that the result is an Int, but your equations give a String result.
There are more mistakes. But that will get you started.
Edit: In response to your first comment:
The type signature should be
remove :: Char -> String -> String
remove takes a Char and a String and gives back a String.
When you put remove :: Char -> String, that means remove takes a Char and gives back a String.
(\elm -> flip (==) elm)
is the same as (\elm -> (==) elm)
is the same as (\elm birch -> (==) elm birch)
is the same as (\elm birch -> elm == birch)
is also the same as (==).
This expression has the type a -> a -> Bool, but you are passing it as the first parameter to filter, which expects a function with type a -> Bool (i.e. it wants a function that takes one parameter, not a function that takes two).
(This is what the error message is telling you about.)

Related

Type mismatch in example from Learning Haskell through Data Analysis

I have a basic knowledge of Haskell (LYAH) and wanted to look at this book to expand my Haskell, plus the general topic is something I enjoy. However it didn't take long before I ran into a type issue :
applyToColumnInCSVFile :: ([String] -> b) -> FilePath -> String -> IO (Either String b)
applyToColumnInCSVFile func inFileName column = do
input <- readFile inFileName
let records = parseCSV inFileName input
return $ either handleCSVError (\csv -> applyToColumnInCSV func csv column) records
where
handleCSVError = Left "This does not appear to be a CSV file."
It complains that handleCSVError is expected to be Text.Parsec.Error.ParseError but actually is Either [Char] b0' .
This is where I hit a wall on trying to figure out the solution to these error messages. I can actually follow the code at a high level in this book, but if I make a small error in writing the code, or there is some other small problem I can not so easily recover.
In the above I have possibly narrowed it down to an issue with parseCSV because when I check that :
http://hackage.haskell.org/package/csv-0.1.2/docs/Text-CSV.html
It shows it can return a ParseError, but I don't know how to resolve the issue.
Let's focus on this part of your code:
return $ either handleCSVError (\csv -> applyToColumnInCSV func csv column) records
where
handleCSVError = Left "This does not appear to be a CSV file."
As #DanielWagner noted in the comments, you misquoted your error message which actually reads:
• Couldn't match expected type parsec3.1.13.0:Text.Parsec.Error.ParseError -> Either String b
with actual type Either [Char] b0
The error message continues to point you to your definition of handleCSVError. You didn't apply a type to it, but let's add one to make more sense of the error message:
return $ either handleCSVError (\csv -> applyToColumnInCSV func csv column) records
where
handleCSVError :: Either String _
handleCSVError = Left "This does not appear to be a CSV file."
I'm using a type hole for the right component of the either since we don't actually care what it is here, and remember that in Haskell [Char] and String are the same type.
Now, let's look at the type of either :: (a -> c) -> (b -> c) -> Either a b -> c.
The first argument of either is a function which takes in something of the left type of your Either, and returns the output type. But you've defined handleCSVError as a static function with no arguments. It has the correct output type c of Either String _ from your larger function, but doesn't specify the argument. There are two ways to fix this:
Use const: ... either (const handleCSVError) ...
Throw away the first argument in your definition of handleCSVError:
handleCSVError :: ParseError -> Either String _
handleCSVError _ = Left "This does not appear to be a CSV file."

Passing any type in function signature in Haskell

I want to pass a function a wildcard or any type or even a way to choose between either of multiple types rather than just restrict it to String, or Number, or Boolean, for example:
myFunction :: a -> String
or
myFunction :: _ -> String
or
myFunction :: (String || Number) -> String
Is that possible?
myFunction :: a -> String is technically possible, however it's profoundly useless – since this must be able to deal with an argument of any type, there's nothing you can actually do with the argument. (It's a bit like getting a can with a completely unspecified substance – you wouldn't eat it in case it's corrosive, you couldn't use it for cleaning purposes in case it's fat, paint or glue, you couldn't process it further... in case of an unrestricted Haskell type you couldn't even analyse it.)
If you narrow it down to types that support some kind of common operation, a polymorphic argument can make sense:
myFunction' :: Show a => a -> String
myFunction' x = "The value is " ++ show x
Your other approach, supporting only two very specific types, is also possible:
myFunction'' :: Either String Integer -> String
myFunction'' (Left s) = "Got a string: “" ++ s ++ "”"
myFunction'' (Right n) = "Got a number: " ++ show n
Note that these two approaches are quite different: Show a => a -> String can be used as String -> String or as Integer -> String, or in fact any other type which supports the show operation (including newly-defined types of your own), but you must decide at compile-time which type you want. At runtime, all arguments passed to this function must then have the same type.
Either String Integer -> String can accept a mixture of String- and Integer values at runtime, but is always restricted to only these two types.
Defining a function a -> String is easily possible, it just won't be able to do anything useful unless you also restrict a to some typeclass (like Show).
_ -> String is not valid syntax. If it were, I imagine it would do the same as a -> String, so you can just use that.
(String || Number) -> String is also not valid syntax, but Either String Number -> String is. You can also define your data type with constructors for the types you want to allow.
myFunction :: a -> String means that myFunction can take an argument of any type, but will always return a string. This is legal Haskell syntax.
With PartialTypeSignatures enabled, myFunction :: _ -> String is legal Haskell syntax, with _ acting as a "hole", or a way to get the compiler to tell you what type it inferred at that position:
Temp.hs:4:15: warning: [-Wpartial-type-signatures]
• Found type wildcard ‘_’ standing for ‘String’
• In the type signature: myFunction :: _ -> String
|
4 | myFunction :: _ -> String
| ^
If you enable TypeOperators, then you can define type (||) = Either, which make myFuncion :: (String || Number) -> String mean that myFuncion is a function that takes an argument of type Either String Number and returns a String:
type Number = Integer
type (||) = Either
myFuncion = (String || Number) -> String
myFuncion (Left string) = string
myFuncion (Right number) = show number

Couldn't match type ‘a’ with ‘Int’ in Haskell

place n x is meant to find the place of integer n in the list x, for example place 2 [1,2,3] will return 1:
place :: Int -> [a] -> Int
place n x = length $ takeWhile (/=n) x
But it gets the error Couldn't match type ‘a’ with ‘Int’
Why? takeWhile should return a list and its length is an integer, hence place should output an Int eventually.
The correct type signature for place is:
place :: Int -> [Int] -> Int
When you use [a] in place of [Int] you are saying that place will work on a list of any type. For instance, I could call it like this:
place 3 [True, False, False, True]
or call it with a list of Char:
place 4 "this is a test"
But neither of these can work because takeWhile will compare each element of the list against the Int n. This forces the list to be a list of Ints.
You are using (/=) :: Eq ty => ty -> ty -> Bool where that second ty ~ Int due to the type of n. If ty is Int then the type of the other argument of (/=) (x) must be Int too.
find the place of integer n in the list x
ah, but there are no integers in the list at all. The type is [a]. Only if the type were [Int] would it be possible to find an n in it.
Now, you might say “[Int] is a possible instantiation of [a], so it could still work in that case”. Well, it could – but only in that case, and therefore it would be stupid not to enforce a ~ Int in the type signature.
More reasonably, you might want to find any type of number which happens to be equal to the integer n. Well, you can do that:
place' :: (Num a, Eq a) => Int -> [a] -> Int
place' n = length . takeWhile (/= fromIntegral n)
Here, I first convert n to the type of number that's contained in the list, and then compare it with those numbers.

Check if a string contains a certain character

I need to check if my string contain a specific character.
I tried this:
charFound :: Char -> String -> Bool
charFound c s = filter(\x -> x == c) s
But it gives me:
Couldn't match expected type Bool with actual type [Char]
I know that filter:
returns a list constructed from members of a list (the second argument) fulfilling a condition given by the first argument.
How could I reach the goal and return a bool instead of a list?
For your purpose, you could use the function elem :: Eq a => a -> [a] -> Bool from prelude. It does exactly what it says on the label. To implement this function, I would use something like this:
elem = any . (==)
or even more elementary:
elem x = foldr ((||) . (x ==)) False
Notice that due to the short-circuit behaviour of (||) this also works with infinite lists as long as x is found.
The type of filter is (a -> Bool) -> [a] -> [a].
You have supplied the first argument which has type Char -> Bool (which is correct), then the second argument which is String (that's [Char]) which is correct, so the type of filter (\x -> x == c) s is [Char].
But the type signature you have provided says the function returns a Bool, which doesn't match the actual type returned.
You probably want to use any instead of filter. It's type is (a -> Bool) -> [a] -> Bool.
There's also an all function that returns True if and only if all elements of the list satisfy the predicate passed. You may also consider the functions or and and that given a [Bool] compute the disjunction or conjunction of the values. So any f = or . map f and all f = and . map f.
For all list-related functions see the Data.List module.

Why do I have to compose id with mapM

I have the following methods:
nucleotideComplement :: Char -> Either String Char
nucleotideComplement 'G' = Right 'C'
nucleotideComplement 'C' = Right 'G'
nucleotideComplement 'T' = Right 'A'
nucleotideComplement 'A' = Right 'U'
nucleotideComplement x = Left "Not a valid RNA nucleotide."
And would like to define another:
toRNA :: String -> String
toRNA = either error mapM nucleotideComplement
However I'm getting a type error here. However doing it this way seems to fix the issue:
toRNA :: String -> String
toRNA = either error id . mapM nucleotideComplement
I don't understand why this happens
First, id has the type a -> a. Next, when getting the type (:t) of mapM nucleotideComplement and id . mapM nucleotideComplement, they seem to be the same. Why am I getting such a different effect?
Hope someone could clarify this further.
I think you're reading this wrong...
either error id . mapM nucleotideComplement
You seem to think this means
either error (id . mapM nucleotideComplement)
when in fact it means
(either error id) . (mapM nucleotideComplement)
You aren't doing id . mapM nucleotideComplement anywhere. You're applying mapM and then passing the result to either, which will apply error or id depending on whether it sees Left or Right.
The type of either is (a -> c) -> (b -> c) -> Either a b -> c. So you apply it to error and you get (b -> c) -> Either String b -> c, then you apply that to mapM and you get Monad m => Either String (a -> m b) -> [a] -> m [b]. Then you apply that to nucleotideComplement and you get an error because nucleotideComplement is a function and not an Either.
In other words you apply either to three arguments when you intended to call it with two arguments where the second argument was the result of applying mapM to nucleotideComplement. To call the function with the arguments you intended, you can write either error (mapM nucleotideComponent), but that still won't work because the second argument to either should be a function accepting a Char (because you have an Either String Char), not one accepting a monad. To achieve what you wanted you can either write either error nucleotideComponent or use . as you already found out.
The version with . works because the precedence rules of Haskell say that either error id . mapM nucleotideComplement is equivalent to (either error id) . (mapM nucleotideComplement), not (either error id . mapM) nucleotideComplement or either error (id . mapM nucleotideComplement). either error id is a function that turns an Either String b into an Either a b where the left case would cause an error and mapM nucleotideComplement is a function that turns an m Char into another m Char with the char being "flipped" for any monad m - in this case m being Either String. So by composing these two functions, you get a function that turns an Either String Char into an Either a Char with the right case being a flipped char and the left case causing an error.
Of course either error flipNucleotide is the far simpler solution.
This doesn't exactly get at your type error, but I'd like to suggest that you reconsider your representation. Specifically, it's generally best to use types to enforce invariants, avoiding partial functions that can throw errors or exceptions, and avoiding accidentally mixing up related things that may belong to different parts of the code. There are various ways to approach this, but here's one. This approach pretends that DNA and RNA have completely different kinds of nucleotides. Chemically, this is not true, but it's probably a sensible representation for what you're doing. Actually encoding the chemical reality is probably beyond the abilities of Haskell's type system, and probably actually less useful for catching mistakes in this context.
data DNANucleotide = GD | CD | TD | AD
data RNANucleotide = GR | CR | UR | AR
toStringDNA :: [DNANucleotide] -> String
toStringDNA = map (\nucleotide -> case nucleotide of
{GD -> 'G'; CD -> 'C'; TD -> 'T'; AD -> 'A'})
toStringRNA = ...
fromCharDNA :: Char -> Maybe DNANucleotide
fromCharDNA 'G' = Just GD
fromCharDNA 'C' = Just CD
...
fromCharDNA _ = Nothing
fromCharRNA = ...
fromStringDNA :: String -> Maybe [DNANucleotide]
fromStringDNA = mapM fromCharDNA
fromStringRNA :: String -> Maybe [RNANucleotide]
fromStringRNA = mapM fromCharRNA
Once you get into the actual mechanics of working with DNA and RNA, as opposed to reading them in from strings, there can be no more errors:
transcribeN :: DNANucleotide -> RNANucleotide
transcribeN GD = CR
transcribeN CD = GR
transcribeN TD = AR
transcribeN AD = UR
transcribe :: [DNANucleotide] -> [RNANucleotide]
transcribe = map transcribeN

Resources