Haskell: Couldn't match type ‘Char’ with ‘[Char]’ - haskell

I'm a Haskell beginner and I'm wrestling using functions to modify a list and then return it back to a string. I'm running into this error however. Any advice?
Couldn't match type 'Char' with '[Char]'
Expected type: String
Actual type: Char
createIndex:: String -> String
createIndex str = unLine (removeT (splitLines str))
splitLines:: String -> [String]
splitLines splitStr = lines splitStr
removeT:: [String] -> [String]
removeT strT = filter (=='t') strT
unLine:: [String] -> String
unLine unLinedStr = unlines unLinedStr

The problem is in your definition of removeT. The type of removeT is [String] -> [String], meaning it works on a list of lists of characters. Then, in your filter, you compare each list of characters (i.e., each String in the list) to a Char ('t'). This is not allowed (you cannot check values with different types for equality).
How to change your code really depends on what you intend to do. It's not entirely clear if you want to remove lines containing t's, if you want to keep lines containing t's, if you want to remove t's, or if you want to keep t's. Depending on what you want to achieve, your code will have to be modified accordingly.
Some pointers:
If you change the type of removeT to String -> String you can look at one line at a time. You would then have to replace removeT in the definition of createIndex by map removeT (because you're applying the function to each line)). In this case, the filter would deal with Char values so comparing with a 't' is allowed.
If you want to do something with lines containing t's, (== 't') is not the way to go, you will want to use ('t' `elem`) (meaning "'t' is an element of").
filter keeps elements matching the predicate. So if you want to remove t's from a string for example, you use filter (/= 't').

Related

How to convert a string to an array containing each character in Haskell?

I was looking at this post here:
Haskell get character array from string?
I see it says that in haskell strings are essentially arrays containing each letter, but I was wondering; how would I turn the format from the string to an array of individual components, for example:
["ABCD","EFGH"]
to
[["A","B","C","D"],["E","F","G","H"]]
I'd like to know a method without using any external imports.
You can wrap each element in a singleton list, so:
map (map pure) ["ABCD", "EFGH"] :: [[String]]
this then produces:
Prelude> map (map pure) ["ABCD", "EFGH"] :: [[String]]
[["A","B","C","D"],["E","F","G","H"]]
That being said, a String is simply a list of Chars, indeed:
type String = [Char]
so if you just want to work with a list of Chars, you can simply work with the string directly. By converting it to a list of list of Strings, we know that all these strings contain one Char, but that is no longer guaranteed by the type.

Haskell: Tail of a String "a"

Why is the tail of a String with only one letter the empty String and not the empty List?
Example:
tail "a"
= ""
But you can create a String as:
'a' : []
= "a"
So I thought the tail should be the empty List [].
And if you do for example
tail ["x"]
then you get the empty List [].
This is a bit confusing.
Because the empty string is the empty list of Chars, it's just shown differently:
Prelude> [] :: String
""
It's because the empty String and empty list of Char are the exact same thing (type String = [Char]). The Show instance for Char takes this into account and overrides the list rendering (using showList) to render as strings. This is why there's no Show instance for String; Show a => Show [a] handles all lists and uses showList [Char].
As an aside, text is a lot more complex than just a string of characters. That approximation was chosen early on in C and Haskell, but other implementations like Data.Text may have better approaches.
When you define an instance of the Show type class you can implement the method showList, which is the way list of that type are display. So:
showList [] = "" -- I guess this is not the actual implementation, but something similar
Regards,

converting a list of string into a list of tuples in Haskell

I have a list of strings:
[" ix = index"," ctr = counter"," tbl = table"]
and I want to create a tuple from it like:
[("ix","index"),("ctr","counter"),("tbl","table")]
I even tried:
genTuple [] = []
genTuples (a:as)= do
i<-splitOn '=' a
genTuples as
return i
Any help would be appriciated
Thank you.
Haskell's type system is really expressive, so I suggest to think about the problem in terms of types. The advantage of this is that you can solve the problem 'top-down' and the whole program can be typechecked as you go, so you can catch all kinds of errors early on. The general approach is to incrementally divide the problem into smaller functions, each of which remaining undefined initially but with some plausible type.
What you want is a function (let's call it convert) which take a list of strings and generates a list of tuples, i.e.
convert :: [String] -> [(String, String)]
convert = undefined
It's clear that each string in the input list will need to be parsed into a 2-tuple of strings. However, it's possible that the parsing can fail - the sheer type String makes no guarantees that your input string is well formed. So your parse function maybe returns a tuple. We get:
parse :: String -> Maybe (String, String)
parse = undefined
We can immediately plug this into our convert function using mapMaybe:
convert :: [String] -> [(String, String)]
convert list = mapMaybe parse list
So far, so good - but parse is literally still undefined. Let's say that it should first verify that the input string is 'valid', and if it is - it splits it. So we'll need
valid :: String -> Bool
valid = undefined
split :: String -> (String, String)
split = undefined
Now we can define parse:
parse :: String -> Maybe (String, String)
parse s | valid s = Just (split s)
| otherwise = Nothing
What makes a string valid? Let's say it has to contain a = sign:
valid :: String -> Bool
valid s = '=' `elem` s
For splitting, we'll take all the characters up to the first = for the first tuple element, and the rest for the second. However, you probably want to trim leading/trailing whitespace as well, so we'll need another function. For now, let's make it a no-op
trim :: String -> String
trim = id
Using this, we can finally define
split :: String -> (String, String)
split s = (trim a, trim (tail b))
where
(a, b) = span (/= '=') s
Note that we can safely call tail here because we know that b is never empty because there's always a separator (that's what valid verified). Type-wise, it would've been nice to express this guarantee using a "non-empty string" but that may be a bit overengineered. :-)
Now, there are a lot of solutions to the problem, this is just one example (and there are ways to shorten the code using eta reduction or existing libraries). The main point I'm trying to get across is that Haskell's type system allows you to approach the problem in a way which is directed by types, which means the compiler helps you fleshing out a solution from the very beginning.
You can do it like this:
import Control.Monda
import Data.List
import Data.List.Split
map ((\[a,b] -> (a,b)) . splitOn "=" . filter (/=' ')) [" ix = index"," ctr = counter"," tbl = table"]

Using the haskell map function with a string

I'm trying to use the map function in haskell
I've got this:
lexi :: String -> [[String]]
lexi x = map (words.lines) x
I want to be able to put a string in to x, so it can be run like this
lexi ("string here")
But get the error
Couldn't match type ‘[Char]’ with ‘Char’
Expected type: String -> String
Actual type: String -> [String]
In the second argument of ‘(.)’, namely ‘lines’
In the first argument of ‘map’, namely ‘(words . lines)’
Couldn't match type ‘Char’ with ‘[Char]’
Expected type: [String]
Actual type: String
In the second argument of ‘map’, namely ‘x’
In the expression: map (words . lines) x
I know that if I use
lexi = map (words.lines)
it works fine when I run lexi ("string here"), but need the variable to use later on
Could some please explain why this doesn't work and how to fix it?
Thank you :)
This answer refers to an old version of the question.
So let's get this quite clear (please always add the type signature of all functions you're talking about!)
function :: Char -> [String]
Well, then the type of map function is [Char] -> [[String]], i.e. String -> [[String]]. But you want the result to be only [String], not a triply-nested list. You probably want to join the lists of two levels together; in general the function to use for list-joining purposes is concat (or more generally, join from the Control.Monad module). In this case, you have two different options:
Join the result of each call to function. I.e., instead of mapping function alone, you map join . function, which has type Char -> String. Mapping that has the desired type String -> [String].
lexi = map $ join . function
Join the final result of the mapping, i.e. lexi = join . map function. This combination of mapping and joining the results is actually an extremely common task, it has a special operator: monadic bind!
lexi x = x >>= function
New version
So we know that
words, lines :: String -> [String]
thus words . lines can not work, because you're trying to feed a list of strings into a function that only accepts a single string. What you can of course do though is map words over the result, i.e. map words . lines. That has in fact the correct signature and probably does just what you want.

Find and replace in Haskell

I want to input a list of 2 element lists of characters (just letters) where the first element is a letter in a String (the second argument for findAndReplace) and the second is what I want it changed to. Is there already a function in Haskell that does a similar thing? Because this would help greatly!
It sounds more like you might want to use a list of tuples instead of a list of lists for your first input, since you specify a fixed length. Tuples are fixed-length collections that can have mixed types, while lists are arbitrary-length collections of a single type:
myTuple = ('a', 'b') :: (Char, Char)
myTriple = ('a', 'b', 'c') :: (Char, Char, Char)
myList = ['a'..'z'] :: [Char]
Notice how I have to specify the type of each field of the tuples. Also, (Char, Char) is not the same type as (Char, Char, Char), they are not compatible.
So, with tuples, you can have your type signature for replace as:
replace :: [(Char, Char)] -> String -> String
And now this specifies with the type signature that it has to be a list of pairs of characters to find and replace, you won't have to deal with bad input, like if someone only gave a character to search for but not one to replace it with.
We now are passing in what is commonly referred to as an association list, and Haskell even has some built in functions for dealing with them in Data.List and Data.Map. However, for this exercise I don't think we'll need it.
Right now you're wanting to solve this problem using a list of pairs, but it'd be easier if we solved it using just one pair:
replace1 :: (Char, Char) -> String -> String
replace1 (findChr, replaceChr) text = ?
Now, you want to check each character of text and if it's equal to findChr, you want to replace it with replaceChr, otherwise leave it alone.
replace1 (findChr, replaceChr) text = map (\c -> ...) text
I'll let you fill in the details (hint: if-then-else).
Then, you can use this to build your replace function using the simpler replace1 function. This should get you started, and if you still can't figure it out after a day or two, comment below and I'll give you another hint.

Resources