So I am trying to program a function in haskell which does the following things:
1. Input is a string
2. function first removes all letters of the string and only numbers remain
3. function converts the string numbers to int numbers
4. function sums the numbers in the string together and prints it out
My Code til' Step #3
func str =
do
str <- filter (< 'a') str
str2 <- map digitToInt str
return str2
somehow this doesn't work if I remove the 4th line with map digitToInt it works til step #2 fine but I dont know what the problem here is
The Error is an couldnt match expected type [Char] with actual type Char
Thank you in advance
You don't want do notation at all, just normal variable binding. So:
func str = str2 where
str1 = filter (<'a') str
str2 = map digitToInt str1
Tracking the most recently used name is annoying, isn't it? Plus it's easy to make a mistake and type str instead of str1 somewhere, or similar. Enter function composition:
func str = str2 where
str2 = (map digitToInt . filter (<'a')) str
In fact, I would inline the definition of str2, then elide str entirely:
func = map digitToInt . filter (<'a')
I would prefer to use isDigit over (<'a'); we can toss in a sum at the same time.
func = sum . map digitToInt . filter isDigit
Reads nice and clean, in my opinion.
You could use do notation, since strings are lists and lists are monads. It would look like this, though:
func :: String -> [Int]
func str = do
c <- filter (< 'a') str -- Get one character
return (digitToInt c) -- Change that character to a integer
What is the value of c? It's not just one character, but all of them. The list monad models nondeterminism. Imagine that func makes multiple copies of itself, with each copy selecting a different character c from the input string. return makes a new list from the result, and the monad takes care of glue the individual lists into a one final list. It's a little clearer if you compare it its deconstructed form.
func str = filter (< 'a') str >>= \c -> return (digitToInt c)
Since xs >>= f = concatMap f xs and return x = [x] in the Monad [] instance, it becomes:
func str = concatMap (\c -> [digitToInt c]) (filter (< 'a') str)
However, the monadic form isn't necessary, as your function only needs to make use of the Functor instance of [], since every element from the first list corresponds to exactly one element in the final list:
-- Or in a form closer to Daniel Wagner's answer
func str = fmap digitToInt (filter (< 'a') str)
Related
Real World Haskell, chapter 4, page 98 of the printed version asks if words can be implemented using folds, and this is my question too:
Is it possible? If not, why? If it is, how?
I came up with the following, which is based on the idea that each non-space should be prepended to the last word in the output list (this happens in the otherwise guard), and that a space should trigger the appending of an emtpy word to the output list if there is not one already (this is handled in the if-then-else).
myWords :: String -> [String]
myWords = foldr step [[]]
where
step x yss#(y:ys)
| x == ' ' = if y == "" then yss else "":yss
| otherwise = (x:y):ys
Clearly this solution is wrong, since leading spaces in the input string result in one leading empty string in the output list of strings.
At the link above, I've looked into several of the proposed solutions for other readers, and many of them work similarly to my solution, but they generally "post-process" the output of the fold, for instance by tailing it if there is an empty leading string.
Other approaches use tuples (actually just pairs), so that the fold deals with the pair and can well handle the leading/trailing spaces.
In all these approaches, foldr (or another fold, fwiw) is not the function that provides the final output out of the box; there's always something else with has to adjust the output somehow.
Therefore I go back to the initial question and ask if it is actually possible to implement words (in a way that it correctly handles trailing/leading/repeated spaces) using folds. By using folds I mean that the folding function has to be the outermost function:
myWords :: String -> [String]
myWords input = foldr step seed input
If I understand correctly, your requirements include
(1) words "a b c" == words " a b c" == ["a", "b", "c"]
(2) words "xa b c" == ["xa", "b", "c"] /= ["x", "a", "b", "c"] == words "x a b c"
This implies that we can not have
words = foldr step base
for any step and base.
Indeed, if we had that, then
words "xa b c"
= def words and foldr
step 'x' (words "a b c")
= (1)
step 'x' (words " a b c")
= def words and foldr
words "x a b c"
and this contradicts (2).
You definitely need some post-processing after the foldr.
#chi has a wonderful argument that you cannot implement words using "a" fold, but you did say using folds.
words = filterNull . words1
where
filterNull = foldr (\xs -> if null xs then id else (xs:)) []
words1 = foldr (\c -> if c == ' ' then ([]:) else consHead c) []
consHead c [] = [[c]]
consHead c (xs:xss) = (c:xs):xss
Both the outermost and innermost function are folds. ;-)
Yes. Eventhough it's a little tricky you may still do this job properly by using a single foldr and nothing else if you dwell into CPS (Continuation Passing Style). I had shown a special kind of chunksOf function previously.
In this kinds of folds our accumulator, hence the result of the fold is a function and we have to apply it to an identity kind of input so that we have the final result. So this may count as a final processing stage or not since we are using a single fold here and the type of it includes the function. Open to debate :)
ws :: String -> [String]
ws str = foldr go sf str $ ""
where
sf :: String -> [String]
sf s = if s == " " then [""] else [s]
go :: Char -> (String -> [String]) -> (String -> [String])
go c f = \pc -> let (s:ss) = f [c]
in case pc of
"" -> dropWhile (== "") (s:ss)
otherwise -> case (pc == " ", s == "") of
(True, False) -> "":s:ss
(True, True) -> s:ss
otherwise -> (pc++s):ss
λ> ws " a b c "
["a","b","c"]
sf : The initial function value to start with.
go : The iterator function
We are actually not fully utilizing the power of the CPS here since we have both the previous character pc and the currect character c at hand in every turn. It was very useful in the chunksOf function mentioned above while chunking a [Int] into [[Int]] every time an ascending sequence of elements were broken.
I am trying to write a function which take a string and returns the original strings without the space character as a list of string e.g.
toStrings "thanks for your help" -> ["thanks", "for", "your", "help"].
I want to solve this problem using an accumulator so I did the following:
toStrings :: String -> [String]
toStrings str = go str []
where
go str acc
| str == [] = acc
| otherwise = go (dropWhile (/=' ') str) acc : (takeWhile (/=' ') str)
It does not work. The compiler says:
Couldn't match type '[Char]' with 'Char'
I thought I was working with Strings.
Help is much appreciated.
Thanks Eitan
takeWhile on a String will return a String. Therefore, you have
go (…) acc : takeWhile (…)
where the latter is a String. However, you need [String] at that point. Since String = [Char], we have the following type mismatch:
String = [Char] -- actual
[String] = [[Char]] -- expected
GHC then sees the [[Char]] and [Char], removes one list layer, and sees [Char] and Char, which cannot get simplified anymore.
That's why you get your error. Type synonyms and simplified types in error messages.
That being said, you never change the acc, nor do you drop the spaces afterwards. Your current implementation will therefore loop infinitely.
I suggest you to solve this problem without an accumulator and instead try to come up with something similar to
-- pseudo code
go str = firstWord str : go (restOfString str)
Keep in mind that firstWord should strip leading spaces, or you end up with an infinite loop.
I think it helps if you add the type to the go function. Based on the function description it should be:
toStrings :: String -> [String]
toStrings str = go str []
where
go str acc :: String -> [String] -> [String]
| str == [] = acc
| otherwise = go (dropWhile (/=' ') str) acc : (takeWhile (/=' ') str)
But in your recursive call, you call (go somestr acc) : someotherstr (I here use somestr and someotherstr to make it easier to see why it does not work). That does not match, since go somestr acc will result in a [String] (given that works), and someotherstr is a String. If you use the cons (:) it expects the head (left operand) to be a String, and the tail (right operand) to be a [String].
But in fact here we do not need to work with an accumulator at all. We can construct a "cons" and perform recursion at the tail, like:
toStrings :: String -> [String]
toStrings ss | null s1 = []
| otherwise = word : toStrings rest
where s1 = dropWhile (== ' ') ss
(word, rest) = span (/= ' ') s1
So first we drop all the spaces of the string ss, which is then s1. In case s1 is the empty list, then we are done, and we return the empty list. Otherwise we perform a span (a conditional split) such that we obtain a tuple with the word as the first item, and the rest of the string as second item. We then yield the word, and perform recursion on the rest.
I'm writing a function to determine whether a number is a palindrome.
What I would like to do in the first case is to destructure the string into the first character, all the characters in the middle, and the last character. What I do is check if the first character is equal to the last, and then if so, proceed to check the middle characters.
What I have is below, but it generates type errors upon compilation.
numberIsPalindrome :: Int -> Bool
numberIsPalindrome n =
case nString of
(x:xs:y) -> (x == y) && numberIsPalindrome xs
(x:y) -> x == y
x -> True
where nString = show n
Using the String representation is cheating...
Not really, but this is more fun:
import Data.List
palindrome n = list == reverse list where
list = unfoldr f n
f 0 = Nothing
f k = Just (k `mod` 10, k `div` 10)
What it does is creating a list of digits of the number (unfoldr is really useful for such tasks), and then comparing whether the list stays the same when reversed.
What you try has several problems, e.g. you miss a conversion from the number to a String (which is just a list of Char in Haskell), and lists work completely different from what you try: Think of them more as stacks, where you usually operate only on one end.
That said, there is an init and a last function for lists, which allow to work your way from the "outer" elements of the list to the inner ones. A naive (and inefficient) implementation could look like this:
palindrome n = f (show n) where
f [] = True
f [_] = True
f (x : xs) = (x == last xs) && (f (init xs))
But this is only for demonstration purposes, don't use such code in real live...
The definition you probably want is
numberIsPalindrome :: Int -> Bool
numberIsPalindrome num = let str = show num
in (str == reverse str)
The (:) operator is known as cons, it prepends items to lists:
1:2:[] results in [1,2]
You are getting a type error because you are trying to compare the first argument, a Char, with the last one, a [a].
If you really would like to compare the first with the last you would use head and last.
But you are better using the solution that taktoa proposed:
numberIsPalindrome :: Int -> Bool
numberIsPalindrome num =
numberString == reverse numberString
where numberString = show num
I'm learning haskell. I'm reading a string from a text file and need to make this string becomes a list of char.
The input file is this:
Individuo A; TACGATCAAAGCT
Individuo B; AATCGCAT
Individuo C; TAAATCCGATCAAAGAGAGGACTTA
I need convert this string
S1 = "AAACCGGTTAAACCCGGGG" in S1 =
["A","A","A","C","C","G","G","T","T","A","A","A","C","C","C","G","G","G","G"]
or S1 =
['A','A','A','C','C','G','G','T','T','A','A','A','C','C','C','G','G','G','G']
but they are separated by ";"
What should I do?
What can I do?
after getting two lists, I send them to this code:
lcsList :: Eq a => [a] -> [a] -> [a]
lcsList [] _ = []
lcsList _ [] = []
lcsList (x:xs) (y:ys) = if x == y
then x : lcsList xs ys
else
let lcs1 = lcsList (x:xs) ys
lcs2 = lcsList xs (y:ys)
in if (length lcs1) > (length lcs2)
then lcs1
else lcs2
A rough and ready way to split out each of those strings is with something like this - which you can try in ghci
let a = "Individuo A; TACGATCAAAGCT"
tail $ dropWhile (/= ' ') $ dropWhile (/= ';') a
which gives you:
"TACGATCAAAGCT"
And since a String is just a list of Char, this is the same as:
['T', 'A', 'C', 'G', ...
If your file consists of several lines, it is quite simple: you just need to skip everything until you find “;”. If your file consists of just one line, you’ll have to look for sequences’ beginnings and endings separately (hint: sequence ends with space). Write a recursive function to do the task, and use functions takeWhile, dropWhile.
A String is already a list of Char (it is even defined like this: type String = [Char]), so you don’t have to do anything else. If you need a list of Strings, where every String consists of just one char, then use map to wrap every char (once again, every String is a list, so you are allowed to use map on these). To wrap a char, there are three alternatives:
Use lambda function: map (\c -> [c]) s
Use operator section: map (:[]) s
Define a new function: wrap x = [x]
Good luck!
How would you go about defining a function that takes two strings, say string x and string y and return the number of elements at the end of the first string (string x) which overlap with the beginning of the second string (second y).
I'm thinking that it would be a good idea to use isPrefixOf from the prelude to do this since it checks if a string is in another string and returns True if it does or False otherwise. But I'm a little confused at how to return the count of how many elements overlap. I wrote some pseudocode based off how I think you would approach the problem.
countElements :: Eq a => (Str a, Str a) -> Int
countElements (x,y) =
if x `isPrefixOf` y == True
then return the count of how many elements overlap
otherwise 0
A sample output would be:
countElements (board, directors) = 1
countElements (bend, ending) = 3
Any help here? I'm not very good at writing Haskell code.
You have exactly the right idea, but your pseudocode misses the fact that you'll have to iterate on all of the possible tails of the first string passed to the function.
countElements :: String -> String -> Int
countElements s t = length $ head $ filter (`isPrefixOf` t) (tails s)
> countElements "board" "directors"
1
> countElements "bend" "endings"
3
Version without isPrefixOf:
import Data.List
countElements xs ys = length . fst . last . filter (uncurry (==)) $ zip (reverse $ tails xs) (inits ys)