Haskell List Comprehension - Ineffective Predicate - haskell

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.

Related

Removing specific elements from lists in Haskell

I'm having a hard time getting Haskell and functional programming together in my head. What I am trying to do is manipulate a string so that I am printing/returning specific characters each time based on a number given. For example:
printing "testing" 2 = "etn"
printing "testing" 3 = "sn"
I've read a lot online, and from what I understand I can achieve this with filtering and cycling, but I cannot get/understand the syntax of this language to get a working program.
I'll try to describe my thought process so you can follow. This function fits the pattern of creating an output list (here a string) from an input seed (here a string) by repeated function application (here dropping some elements). Thus I choose an implementation with Data.List.unfoldr.
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
Okay so, I need to turn the seed b into (Maybe) an output a and the rest of the string. I'll call this subfunction f and pass it into unfoldr.
printing s n = unfoldr f s
where f b = case drop n b of
[] -> Nothing
(x:xs) -> Just (x,xs)
It turns out that attempting to take the head off the front of the list and returning a Maybe is also a common pattern. It's Data.List.uncons, so
printing s n = unfoldr (uncons . drop n) s
Very smooth! So I test it out, and the output is wrong! Your specified output actually eg. for n=2 selects every 2nd character, ie. drops (n-1) characters.
printing s n = unfoldr (uncons . drop (n-1)) s
I test it again and it matches the desired output. Phew!
To demonstrate the Haskell language some alternative solutions to the accepted answer.
Using list comprehension:
printing :: Int -> String -> String
printing j ls = [s | (i, s) <- zip [1 .. ] ls, mod i j == 0]
Using recursion:
printing' :: Int -> String -> String
printing' n ls
| null ls' = []
| otherwise = x : printing' n xs
where
ls' = drop (n - 1) ls
(x : xs) = ls'
In both cases I flipped the arguments so it is easier to do partial application: printing 5 for example is a new function and will give each 5th character when applied to a string.
Note with a minor modification they will work for any list
takeEvery :: Int -> [a] -> [a]

Haskell : Filtering a list of strings

I have a list of Strings I want to filter through. My predicate is that the string should begin with an uppercase letter.
eg. when I run onlyLowercase ["boy", "girl", "Hi"]
it should give me a list of ["boy", "girl"]
I can do it using pattern matching and guards, but I'm using the learnyouahaskell (http://learnyouahaskell.com) book and I came across the topic on higher-order functions. I read about the filter function and thought it could achieve what I want to do in far fewer lines of code.
Using pattern Matching/Guards (This works well and solves my problem)
onlyLowercase :: [[Char]] -> [[Char]]
onlyLowercase [] = []
onlyLowercase (x:xs)
| isLower (head x) = x : onlyLowercase xs
| otherwise = onlyLowercase xs
Using the filter function
onlyLowercase2 :: [String] -> [String]
onlyLowercase2 [] = []
onlyLowercase2 (x:xs) = filter isLower x : onlyLowercase2 xs
Unfortunately, when I run onlyLowercase2 ["boy", "girl", "Hi"],
I get a list of ["boy", "girl", "i"].
I want to know if there's a way I can filter my list of strings using the first character in my string (without creating any auxiliary function that could check the String and return true if the first letter is lowercase).
I also tried using
onlyLowercase2 (x:xs) = filter (isLower head x) : onlyLowercase2 xs
but that didn't even compile. Basically, I'm just trying to figure out how the filter function can be used on a list of lists. Thank you, in advance, for any assistance rendered.
Thanks to Willem Van Onsem's suggestion to use a lambda expression as a filter function, I read further and came up with this 2 line solution.
onlyLowercase2 :: [String] -> [String]
onlyLowercase2 = filter (\st-> ("" /= st) && (isLower $ head st))
Not sure if it's perfect, but at least it's working.
Using Data.List and Data.Char:
import Data.List
import Data.Char
onlyLowerCase :: [String] -> [String]
onlyLowerCase = filter (all isLower)
I use the all function which checks that all elements of a list satisfy a predicate. In this case all isLower will return true if all letters in a String are lowercase. Then just filter the Strings that are all lowercase. The Haskell Report has a good reference for List and Char functions among other useful libraries.

Printing a list in Haskell

I'm sure these are both very stupid mistakes, but i'm trying to convert and print two lists , and i'm getting an error on ghci.
First, i want to convert from this:
["2","2","2"]
to this
[2,2,2]
for that, i wrote this function:
convert (x:xs) = [read x | x <- xs]
but that doesn't seem to be working...
Second:
Here's my printing function:
print_results [] _ = error("Empty List!")
print_results _ [] = error("Empty List!")
print_results (x:xs) (y:ys) = print x ++ " + " ++ print y : print_results xs ys
For this input:
[2,2,2] and [3,3,3]
The desired output should be:
2 + 3
2 + 3
2 + 3
Thanks in advance!
These are not "stupid" mistakes, but you're going to have to step back a bit from "what type do I write here" in order to make sense of what's going on. I notice you've asked a bunch of overlapping questions today surrounding these issues. I hope we as a community can get you an answer that will get you on the right track. In that light, I'm marking this post Community Wiki and encouraging others to edit it.
In Haskell, every value has a specific, concrete type. We can write functions that work on multiple types. Some of them work on all types: replicate 5 :: a -> [a] doesn't care at all about what a is. Some work only on some types: read :: Read a => String -> a requires that a be an instance of the class Read.
For now, you should assume that, in order to actually run a function and print a result in GHCi or compiled code, you need to replace all type variables to specific types. (This is wrong in lots of ways that I or others will probably expand on.)
After writing a function, ask GHCi for its inferred type, which is usually the most general signature possible:
> :t map read
map read :: Read a -> [String] -> [a]
> :t map read $ ["as","ew"]
> map read $ ["as","ew"] :: Read a => [a]
Notice that we still have a type variable in there. We need to choose a specific type. What #chi and I both encouraged you to do was to add a type annotation somewhere to fix that type. But if you fix that type to Int, you're trying to parse "as" and "ew" as numbers, which obviously fails.
First:
convert :: [String] -> [Int]
convert xs = [read x | x <- xs]
or even
convert :: [String] -> [Int]
convert = map read
Note that the type annotation matters, since without it Haskell does not how how it should read the string (as an Int? a Char? a tree? a list? etc.)
Second:
print_results [] [] = []
print_results [] _ = error "Empty List!"
print_results _ [] = error "Empty List!"
print_results (x:xs) (y:ys) = (show x ++ " + " ++ show y) : print_results xs ys
The above will compute a list of strings, formatted as you wanted. If you really want to print them doing an IO action, you can use
mapM_ putStrLn (print_results list1 list2)

Little problems from a Haskell learner about filter & fold

This is my second day learning Haskell and I am stuck terribly by a problem.
I tried to solve the eighth problem in 99 Haskell questions
The problem is to write a function called "compress" which works like this:
>compress "aaaabbbbccccddddd"
"abcd"
>compress [1,1,1,1,2,3,4,4,4,4]
[1,2,3,4]
and here's what I wrote:
compress :: (Eq a) => [a] -> [a]
compress [] = []
compress x = filter ( (head x) `notElem` ( compress $ tail x ) ) x
The compiler said:
Couldn't match expected type a -> Bool' with actual type Bool'
In compress, I tried to recursively pick up new elements from end to head. (like backtracking maybe??)
Is my algorithm wrong?
Is there alternative way to implement the algorithm in a more readable way?
(Like: where to put parentheses? or $ )
Can someone kindly help me with it?
Thanks a lot.
Thanks to Lubomir's help, I corrected my code by :
compress'(x:xs) = x : compress' (dropWhile (== x) xs)
and it works!
And thanks everyone, I feel spoiled! You guys are so kind!
I'll keep on learning Haskell!
Is there alternative way to implement the algorithm in a more readable
way?
Yes.
import Data.List
compress :: Eq a => [a] -> [a]
compress = map head . group
map head . group is basically \xs -> map head (group xs). group xs will create a list of lists were all equal consecutive elements are grouped together in a list. map head will then take the heads of these lists discarding the rest as required.
The algorithm is basically fine, but it does not typecheck. The first argument to filter should be a function of type a -> Bool – for an element of the list it should tell you whether or not to throw it out. What you have is a single Bool value.
The second part of the function may be better implemented with a different pattern. This would allow you to drop the head and tail functions.
compress [] = []
compress (x:xs) = x : compress (filter (/= x) xs)
This pattern binds x to the first element of the list and xs is the tail of the list. The function should include x in the result and recursively call itself on filtered xs (with x removed from it).
EDIT: this function does not do what the problem requests. Only consecutive duplicates should be eliminated. This can be fixed by using dropWhile instead of filter and slightly modifying the predicate function.
Check the signature of filter:
Prelude> :t filter
filter :: (a -> Bool) -> [a] -> [a]
Note that the first argument must be a function. Now check the type of your expression within the paranthesis.
Prelude> :t notElem
notElem :: Eq a => a -> [a] -> Bool
Thus, notElem a b will return a value of type Bool.
Note: I think you might have misunderstood the problem statement. What is the expected output for aaabbbaaa?
I would argue it should be aba, as the problem is stated as
Eliminate consecutive duplicates of list elements.
(emphasize mine).

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