Using the bind function to process a list - haskell

I am trying to convert a String of numbers (e.g. "2 3 9 10 14") into a list of Maybe [Token]. I have the following code where the function parseToken converts a String into a Maybe Token.
data Token = Num Int
parseToken :: String -> Maybe Token
parseToken str = fmap Num (readMaybe str)
For converting the String into a list of Maybe [Token], I have the following code below:
tokenise :: String -> Maybe [Token]
tokenise str = do
let (x:xs) = words str
y <- parseToken x
ys <- parseToken xs
return (y:ys)
I am trying to use the bind (>>=) function to do this. Initially I convert the string into a list of strings, using the words function. I then apply parseToken to the first element of the list, with the result (i.e. the Token value) of this stored in y.
However, I am not sure how I can apply parseToken to the rest of the list using bind. In general, if one wants to apply a function to every element of a list, while taking in the context of failure, and then join the results into a new list -
what is the best way to do this?
Any insights are appreciated.

You have merged two separate concerns in one function here:
Separating a string into components, and
turning each component into a token.
That's all fine and normal so far. What I would recommend, though, is splitting step (2) out into a separate function, and implementing your top-level thing in terms of it. So:
parseTokens :: [String] -> Maybe [Token]
parseTokens [] = ...
parseTokens (x:xs) = ...
I think you will find it easier to implement this than implementing tokenise wholesale, because when it comes time to deal with xs, you will find that you already have a function that does the thing you need on it. I recommend taking a stab at implementing this function; if you have trouble, then perhaps a fresh question with your attempt and why you believe it's not possible to make progress on it would be warranted.
Once you've done that, you can drop this function in place in your existing tokenise implementation:
tokenise str = do
let (x:xs) = words str
parseTokens (x:xs)
Of course, at this point there's no reason to pattern match on the result of words like that, since you just plan to pass on the result anyway:
tokenise str = do
let xs = words str
parseTokens xs
Most people would then inline xs,
tokenise str = do
parseTokens (words str)
drop the superfluous do,
tokenise str = parseTokens (words str)
and make it point-free.
tokenise = parseTokens . words

Related

Transforming a string into a list of pairs comprising the character from each run together with its number of repetitions

So I am required to convert a list of strings to a [(Char,Int)]. So for example, ["xxxxx","yyy"] to [('x',5), ('y',3)] . I am able to get the ('x',5) part without any issues but I am not sure how to move on to the next element of the list. Here is my code so far. Any pointers will be greatly appricated.
[(x,y) | let x = head(head(reap xs)), let y = length(head(reap xs)))]
p.s : reap is a function that turns a string into a list of repeated characters. For example "aaaabbbbccc" -> ["aaaa","bbbb","bbb"].
I suggest breaking this into smaller parts. First define a function that takes a single String and returns a tuple (Char, Int). Then once you have this function , you can use map to apply it to each String in a list.
You can use the fmap function which applies a function over or any item in the list.
The function charRepetitions accepts a list and uses the charRepetition function to transform an item.
main = do
_ <- print $ charRepetitions ["xxxxx","yyy"]
return ()
charRepetitions :: [String] -> [(Char, Int)]
charRepetitions xs = fmap charRepition xs
charRepetition :: String -> (Char, Int)
charRepetition s = (head s , length s)

Do notation in haskell

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)

Split string to a list of strings in Clean

Because of the limited amount of resources, I need to propose a question here. I have been struggling with functional programming, the endless Haskell tutorials don't really help me. So what I want to achieve, in Clean language, is to split a string like " car cow cat " to a list of strings ["car","cow","cat"]. Can you provide me a detailed answer (does not have to be complete code), on how to iterate through this string, and especially the part when the newly constructed strings are added to the list?
I'm going to offer a simple solution. There are infinitely better ways of doing this in Haskell, but it's the simplest I can think for someone new in functional programming, without using any specifically Haskell function like takeWhile, or even any folds and maps...
You basically want to simulate iterating over a list, so here is what I suggest:
Define a function that will take a string and a split-by character. This function will return a list of strings - spliton :: String -> Char -> [String]
To move over the list, we'll want to gobble up characters until we hit one of our splitting characters. We'll also want to save the word we've saved up until now, and the entire list of words.
For that, we'll define a subfunction that will save the states
spliton' :: String -> Char -> String -> [String] -> [String]
spliton' [] _ sofar res = res ++ [sofar]
I've also included the simplest clause - an empty string. When our string is empty, we'll just want to return what we have saved so far.
Now lets move on to our actual recursive function:
If we hit our split character, we'll add the string we have saved so far to the list and restart with an empty current-state string
If we don't hit the split character, we'll add the character to the current-state string
spliton' (currchar:rest) splitby sofar res
| currchar==splitby = spliton' rest splitby "" (res++[sofar])
| otherwise = spliton' rest splitby (sofar++[currchar]) res
So, to summarize our code:
spliton :: String -> Char -> [String]
spliton source splitchar = spliton' source splitchar [] []
spliton' :: String -> Char -> String -> [String] -> [String]
spliton' [] _ sofar res = res ++ [sofar]
spliton' (currchar:rest) splitby sofar res
| currchar==splitby = spliton' rest splitby "" (res++[sofar])
| otherwise = spliton' rest splitby (sofar++[currchar]) res
Note: This will not however get rid of the empty string - meaning if you have many superfluous spaces - you'll get them added to the list. I'll leave you to think how to handle that case - hope this can help you get started.
Let's split this up in several sub-problems:
Make a list of characters from the string so that we can easily apply pattern matching.
Scrape the initial part of the list (as long as possible with only spaces or only not-spaces), and only keep it when it is not whitespace.
Repeat the second step while the list is non-empty.
The first thing can be done using fromString. For the second and third step, we define a helper function:
scrape :: [Char] -> [String]
scrape [] = []
scrape cs=:[c:_]
| isSpace c = scrape (dropWhile isSpace cs)
| otherwise = [toString word:scrape rest]
where
(word,rest) = span (not o isSpace) cs
The first alternative is the base case to match the empty list. The second alternative matches the whole list cs with a first element c. If the first character is a space, we recursively (step 3) call the same function on the same list without the initial part of spaces. If the first character is not a space, we use span :: (a -> Bool) [a] -> ([a], [a]) to split the list in the initial part that is a word, and the rest. We store the word using toString as a string, and recursively call scrape for the rest of the list.
Now, we only need a wrapper to make this a function with the type String -> [String]:
split :: String -> [String]
split s = scrape (fromString s)
where
scrape :: [Char] -> [String]
scrape [] = []
scrape cs=:[c:_]
| isSpace c = scrape (dropWhile isSpace cs)
| otherwise = [toString word:scrape rest]
where
(word,rest) = span (not o isSpace) cs
Note that you can easily abstract from the delimiter, by passing a character d and replacing isSpace c with c == d and (not o isSpace) by ((<>) d). Alternatively, you can choose to not pass a character d but a function isDelim :: Char -> Bool. You then get isDelim c and (not o isDelim), respectively.

Haskell List Comprehension - Ineffective Predicate

I'm pretty brand new to Haskell (only written a fizzbuzz program before the current one) and am trying to write a program that takes the unix wordlist ('/usr/share/dict/words') and prints out the list of anagrams for that word, with any direct palindromes starred. I have the meat of this summed up into one function:
findAnagrams :: [String] -> [(String, [String])]
findAnagrams d =
[x | x <- map (\s -> (s, [if reverse s == t then t ++ "*" else t | t <- d, s /= t && null (t \\ s)])) d, not (null (snd x))]
However, when I run the program I get this output:
abase: babes, bases
abased: debase
abasement: basements
abasements: abatements
abases: basses
And so on, so clearly it isn't working properly. My intention is for the list comprehension to read as follows: for all t in d such that t is not equal to s and there is no difference between t and s other than order, if t is the reverse of s include as t*, otherwise include as t. The problem seems to be with the "no difference between t and s other than order" part, which I'm trying to accomplish by using "null (t \ s)". It seems like it should work. Testing in GHCI gives:
Prelude Data.List> null ("abatements" \\ "abasements")
False
And yet it passes the predicate test. My assumption is that I'm missing something simple here, but I've looked at it a while and can't quite come up with it.
In addition, any notes regarding best practice would be greatly appreciated.
If you break it out into multiple functions (remember, source code size is not really that important), you could do something like:
import Data.List
isPalindrome :: String -> Bool
isPalindrome s = s == reverse s
flagPalins :: [String] -> [String]
flagPalins [] = []
flagPalins (x:xs)
| isPalindrome x = x ++ "*"
| otherwise = x
isAnagram :: String -> String -> Bool
isAnagram s t = (isPalindrome s || s /= t) && ??? -- test for anagram
findAnagrams :: String -> [String] -> [String]
findAnagrams s ws = flagPalins $ filter (isAnagram s) ws
findAllAnagrams :: [String] -> [(String, [String])]
findAllAnagrams ws = filter (not . null . snd) ??? -- words paired with their anagrams
I've intentionally left some holes for you to fill in, I'm not going to give you all the answers ;)
There are only two spots for you to do yourself. The one in findAllAnagrams should be pretty easy to figure out, you're already doing something pretty similar with your map (\s -> ...) part. I intentionally structured isAnagram so it'll return True if it's a palindrome or if it's just an anagram, and you only need one more check to determine if t is an anagram of s. Look at the comment I made on your question for a hint about what to do there. If you get stuck, comment and ask for an additional hint, I'll give you the name of the function I think you should use to solve this problem.
If you really want to make a list comprehension, I would recommend solving it this way, then converting back to a comprehension. In general you should write more verbose code, then compress it once you understand it fully.
Think of a \\ b as "items in a that are not in b."
Consider the implications.

Iterating through a String and replacing single chars with substrings in haskell

I am trying to learn some Haskell and I find it difficult. I am having some issues with my
current project. The idea is that I have to go through a String and substitute certain chars
with new substrings. For instance if I have a String "FLXF" and I want to replace every F
with a substring called "FLF" the result should be "FLFLXFLF". Now I have been working on this
specific problem for hours. I have been reading up on types, different functions that might come in handy (map, fold, etc) and yet I have not been able to solve this problem.
The code below is some of the different tries I have had:
apply :: String -> String
apply [] = []
apply (x:xs) = if (x == 'F')
then do show "Hello"
apply xs
else (apply (xs))
This example here I was just trying to show hello every time I encountered a 'F', but all it shows is "", so this clearly does not work. I am really not sure an if else statement is the way to go here. I was also thinking the function map might do the trick. Here the code I was thinking about could look something like this:
map (\x y -> if y == 'F' then "FLD" else y) "FLF"
but that gives me a type error. So as you can see I am lost. Excuse me my poor knowledge to Haskell, but I am still new to it. I really hope some of you can help me out here or give me a push in the right direction. Feel free to ask questions if I have been unclear about something.
Thank you in advance!
John
map (\x y -> if y == 'F' then "FLD" else y) "FLF"
This is nearly right.
First... why does the function take two arguments?
map (\y -> if y == 'F' then "FLD" else y) "FLF"
The remaining type error is because the then branch gives a String, but the else branch gives a Char (the two branches must each give a value of the same type). So we'll make the else branch give a String instead (recall that String is a synonym for [Char]):
map (\y -> if y == 'F' then "FLD" else [y]) "FLF"
Now the problem is that this gives you a [String] value instead of a String. So we'll concatenate all those strings together:
concat (map (\y -> if y == 'F' then "FLD" else [y]) "FLF")
This combination of concat and map is common enough that there's a standard function that combines them.
concatMap (\y -> if y == 'F' then "FLD" else [y]) "FLF"
concatMap is the most intuitive thing here. This kind of combination between mapping over a data structure a function that does itself return the type of the data structure (in this case, a list) and combining the results back into a single "tight" list is indeed very common in Haskell, and indeed not only for lists.
I'd like to explain why your first attempt compiles at all, and what it actually does – because it's completely different from what you probably think!
apply (x:xs) = if (x == 'F')
that line is still perfectly clear: you just take the first char off the string and compare it to 'F'. At bit "pedestrian" to manually take the string apart, but fine. Well, the name you gave the function is not particularly great, but I'll stick with it here.
then do show "Hello"
now this is interesting. You probably think do starts a list of points, "first do this, then do that"... like in simple Hello, World-ish example programs. But always remember: in Haskell, there's normally no such thing as an order in which stuff is calculated. That only happens in the IO context. But there's no IO in your code!?!
Not sure if you've heard about what IO actually is, anyway here you go: it's a Monad. Those "mythical Haskell constructs you've only read about in story books"...
Indeed, though this might lead a bit far here, this question covers all there is to know about Monads! How is that?
Here's another (correct!) way do define your function.
apply' str = do
x <- str
if (x == 'F')
then "FLF"
else return x
So I'm using this weird do syntax, and it's not in IO, and it looks completely different from what you'd write in IO, but it works. How?
x <- str
In do notation, variable <- action always means something like "take one value out of this monadic thingy, and call it x". What you've probably seen is something like
response <- getLine
which means "take a user input out of the real world (out of the IO monad!) and call it response". In x <- str, it's a string that we have, not an IO action. So we take a character out of a string – nice and easy!
Actually, it's not quite right, though. "take a character" is what you do with apply (x:xs) = ..., which simply takes the first one. In contrast, x <- str actually takes all possible characters out of the string, one by one. If you're used to procedural languages, this may seem very inconsistent with response <- getLine, but in fact it's not: getLine also consists of every possible input that the user might give, and the program has to act according to this.
if (x == 'F')
nothing unexpected here, but
then "FLF"
whoah! Just like that? Let's first look at the next line
else return x
ok, this looks familiar, but actually it's not. In other languages, this would mean "we're done with our function, x is the result". But that's obviously not what happens here, because x is Char, and the "return type" of apply' is String. In Haskell, return actually has little to do with returning values from a function, instead it means "put that value into the monadic context that we're working in". If the monad were IO, that would be quite the same: give this value back to the real-world context (this does not mean to print the value or something, just to hand it on). But here, our context is a string, or rather a list (of chars, so it is a String).
Right, so if x is not 'F' we put it back into the string. That sounds reasonable enough, but what about then "FLF"? Note that I can also write it this way:
if (x == 'F')
then do
x' <- "FLF"
return x'
else return x
which means, I take all characters out of "FLW" and return them back into the overall result. But there's no need to only think about the final result, we can as well isolate only this part do { x' <- "FLF"; return x' } – and, quite obviously, its value is nothing but the string "FLF" itself!
So I hope you have now grasped why apply' works. Back to your version, though it actually doesn't make much sense...
then do
show "Hello"
apply xs
here we have a line that's not at the end of a do block, but doesn't have a <- in it. You normally see this in IO in something like
main = do
putStrLn "How ya doin'?"
response <- getLine
...
Remember that "output-only" actions have type IO() in Haskell, which means, they don't directly return any meaningful value, just the trivial value (). So you don't really care about this, but you could still evaluate it:
main = do
trivial <- putStrLn "Hello, let's see what this IO action returns:"
print trivial
compiles and outputs
Hello, let's see what this IO action returns:()
It would be stupid if we had to do this evaluating () all the time, so Haskell allows to just leave the () <- out. It's really just that!
So a line like show "Hello" in the middle of a do block basically means "take one character out of show "Hello" (which is simply a string with the value "\"Hello\""), but don't do anything else with this character / just throw it away".
The rest of your definition is just other recursive calls to apply, but because none of them does anything more interesting than throwing away characters, you eventually end up at apply [] = [], so that's the final result: an empty string.
if-then-else... I know that Haskell supports these, however, I'm very surprised that no one here removed them...
So below are my solutions for different cases of making replacements.
Replacing a character
Replacing words
Replacing through a function on each word
$ cat replace.hs
import Data.List (isPrefixOf)
replaceC :: Char -> Char -> String -> String
replaceC _ _ [] = []
replaceC a b (x:xs)
| x == a = b:replaceC a b xs
| otherwise = x:replaceC a b xs
replaceW :: String -> String -> String -> String
replaceW a b s = unwords . map replaceW' $ words s
where replaceW' x | x == a = b
| otherwise = x
replaceF :: (String -> String) -> String -> String
replaceF f = unwords . map f . words
string = "Hello world ^fg(blue)"
main = do
print string
print $ replaceC 'o' 'z' string
print $ replaceW "world" "kitty" string
print . replaceF f . replaceW "world" "kitty" $ replaceC 'H' 'Y' string
where f s | "^" `isPrefixOf` s = '^':'^':drop 1 s
| otherwise = s
$ runhaskell replace.hs
"Hello world ^fg(blue)"
"Hellz wzrld ^fg(blue)"
"Hello kitty ^fg(blue)"
"Yello kitty ^^fg(blue)"
Your basic error was that you wanted to replace a Char in a String with a String.
This is impossible because String is a list of Char and a Char is a Char and not a short String. Neither is a String ever a Char, even if its length is 1.
Hence, what you really wanted is to replace some Char with some other Chars. Your approach was promising and could have been completed like so:
replace [] = [] -- nothing to replace in an empty string
replace (c:cs) = if c == 'F' then 'F':'L':'F':replace cs
else c:replace cs

Resources