No instance for Foldable arising from length inside lambda - haskell

first question here and completely a noob on haskell, so please be kind with me :)
I was playing with the question number 6 of this haskell exercises
and in the end came to the solution (or something similar I hope) with this code
combinations gr lis = filter clean $ sequence $ replicate gr lis
where
clean string
| total > gr = False
| otherwise = True
where total = sum [ rpt c string | c <- string]
rpt chr list = length $ filter (== chr) list
the part that i like to be highlighted is the function 'rpt' which counts the number of times a character is repeated in a string, for example:
"aaba" -> [3313] (the 3 comes from the letter a, which repeates 3 times)
"aaccva" -> [332213]
later on I tried to make the function with a lambda and a map resulting in this:
rpt chr list = map (\chr -> length $ filter (== chr)) list
and at first ghci told me to use FlexibleContext to allow this, but if I do then it yields:
<interactive>:7:1:
No instance for (Foldable ((->) [Char]))
arising from a use of ‘rpt’
In the expression: rpt 'a' string
In an equation for ‘it’: it = rpt 'a' string
and here I'am stuck, I have not been able to understand what's happening... what is needed to fix this function?

You likely are intending to filter over list, so to make your code work, you need to also add list as an argument of filter:
rpt chr list = map (\chr -> length $ filter (== chr) list) list
For beginners, I recommend ignoring GHCi's suggestion of FlexibleContexts. It often ends up producing error messages like the one you had (or other confusing ones like No instance for (Num (Int -> Bool))).

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]

Take all numbers from a string and present them in a list

I was doing some Haskell exercises but can't solve the last one.
I need to recursively define functions that are already defined in the Data.Char module.
The last function I need to define is of this type:
nums :: String -> [Int]
Here is the (translated) question:
Using functions from the Data.Char module, define recursively the following functions:
(c) nums :: String -> [Int] which receives a string and outputs a list
with the algarisms that occur on that string, by the same order.
--This is my code
numbers :: String -> [Int]
numbers [] = []
numbers (l:ls) = if ord l >= 48 && ord l <= 57
then l : (numbers ls)
else (numbers ls)
I've been getting this error on the interpreter:
pratica3.hs:137:14:
Couldn't match expected type `Int' with actual type `Char'
In the first argument of `(:)', namely `l'
In the expression: l : (numbers ls)
In the expression:
if ord l >= 48 && ord l <= 57 then
l : (numbers ls)
else
(numbers ls)
Failed, modules loaded: none.
Thank you.
Since this is a class problem, here are some hints. Use the function words to first break the string into individual elements, drop all non-numeric characters, then read "elem":Int for each element of your string and filter out those that return false. What's left will be [Int].
The magic as is obvious is in the read function that takes a char representation of numbers and converts them to Int. If you have very large numbers, consider using read "elem":Integer variation.
Ok,
The solution is:
numbers :: String -> [Int]
numbers [] = []
numbers (l:ls) = if ord l >= 48 && ord l <= 57
then (ord l - 48): (numbers ls)
else (numbers ls)
This solves my problem, which is (and now I'll try to explain it better):
Using functions from the Data.Char module, define recursively the
following functions:
(c) nums :: String -> [Int] which receives a string and outputs a list
with the algarisms that occur on that string, by the same order.
Please keep in mind that this was made for students that had less than 8 hours of contact with the haskell language and 0 with any other language.
If this is incorrect, I would appreciate any answer. I want to learn.
Note: this solution doesn't seem to be the most complete. Alas, it is made for students that just started learning Haskell and don't know how to use the words and map functions.

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.

Haskell compare all list items

Edit: it's hard to describe what I'm trying to do, but here's a try (from the comments):
I am building a wordfeud solver, so I have a word, and some letters (both char list). I applied this ( How to find the frequency of characters in a string in Haskell? ) to both lists to get the frequency of all letters. What I'm doing now is iterating though the 'word' char list, and checking if all chars occur sufficiently in the 'letters' char list.
I have written a Haskell function that compares two lists by applying a function to the items of both lists, and comparing the results.
The comparison is done like this:
hasLetters' :: [Char] -> [Char] -> Bool
hasLetters' word letters = (getCharOccurrence (head word) (getCharOccurrences word)) <= (getCharOccurrence (head word) (getCharOccurrences letters))
This only compares the occurrences of the first letter of the word. But ALL words should be compared (and the result should be TRUE for all of them).
I don't really know how to accomplish this. I found the 'all' method that lets me define a predicate, that's pretty good. It looks like this:
all (<= (getCharOccurrence (head word) (getCharOccurrences letters)))
(I think that's correct)
It makes sure that every item that goes into the list is smaller than or equal to the result of the provided function.
BUT: the 'all' method needs another parameter. This would be the 'source' parameter that defines what should be compared to the predicate. This would be easy when this were just a list, then I would do something like this:
all (<= (getCharOccurrence (head word) (getCharOccurrences letters))) [0..10]
But the problem is: I dont have a list of results like this, I need to compare it to the result of:
(getCharOccurrence (head word) (getCharOccurrences letters))
I figured that I could apply this function to every character in the 'word' char list with the 'map' function, but I dont know how to use it. I started like this:
map (getCharOccurrence (head word) (getCharOccurrences word)) word
But that's wrong.
So what I (think I) need: apply the above function to all characters of the 'word' char list, and compare it to the predicate.
But maybe I'm just think the wrong way. I'm an absolute Haskell/functional programming newbie. Please help me out :-)
Using the multiset package:
import Data.MultiSet
compareAll as bs = fromList as `isSubsetOf` fromList bs
or:
import Data.Function
import Data.MultiSet
compareAll = isSubsetOf `on` fromList
So from what I understand you have a string word with the word you would like to form and a list of chars letters representing the tiles at your disposal. You want to check whether the word may be formed by the tiles or not.
Here I'm assuming the functions you've mentioned have the types
getCharOccurrence :: Char -> [(Char, Integer)] -> Integer
getCharOccurrences :: [Char] -> [(Char, Integer)]
First, you need to modify hasLetters' to take a Char parameter instead of using head word:
hasLetters' :: Char -> [Char] -> [Char] -> Bool
hasLetters' c word letters = (getCharOccurrence c (getCharOccurrences word)) <= (getCharOccurrence c (getCharOccurrences letters))
Then you can combine the above to a master function (let's call it sufficientTiles) with
sufficientTiles :: [Char] -> [Char] -> Bool
sufficientTiles word letters = and $ map (\c -> hasLetters' c word letters) word
What we've done here is to map the hasLetter' function to each character of word. This will give us a list of Bools. We then use and to check that all elements of that list are True.
So I think I understand that you want to compare two lists. The test passes if the second list has at least as many of each element as the first list. Thus, you need a constraint of at least equality but order would help.
There are many solutions, the one that comes to mind first is sort each list, group and count the unique elements, and ensure all results are <=:
someCompare a b = let op :: String -> [(Char,Int)]
op = map (head &&& length) . group . sort
in [c <= k | (x,c) <- op a, k <- maybeToList (lookup x (op b))]
Or you can use a map of counters and union the two maps:
someCompare2 a b =
let op = foldl' (\m c -> Map.insertWith (+) c 1 m) Map.empty
in all (<= 0) . Map.elems $ Map.unionWith (+) (op a) (Map.map negate $ op b)
Etc etc.

Character & strings

I am new in haskell and I have a problem (aka homework).
So, I have a list with a tuple – a string and an integer:
xxs :: [([Char], Integer)]
I need to know how many of the strings in xxs start with a given character.
Let me exemplify:
foo 'A' [("Abc",12),("Axx",34),("Zab",56)]
Output: 2
foo 'B' [("Abc",12),("Bxx",34),("Zab",56)]
Output: 1
My best attempt so far:
foo c xxs = length (foldl (\acc (x:xs) -> if x == c then c else x) [] xxs)
But, of course, there's something VERY wrong inside the lambda expression.
Any suggestion?
Thanks.
You can use a fold, but I would suggest another way, which breaks the problem in three steps:
transform the input list to the list of first letters. You can use map for this
filter out all elements not equal to the given Char
take the length of the remaining list
Obviously the first step is the hardest, but not as hard as it looks. For doing it you just have to combine somehow the functions fst and head, or even easier, map twice.
You can write this as a simple one-liner, but maybe you should start with a let:
foo c xxs = let strings = map ...
firstLetters = map ...
filteredLetters = filter ...
in length ...
There are a few problems with your attempt:
You plan to use foldl to construct a shorter list and then to take its length. While it is possible, filter function is much better suited for that task as #landei suggests
foldl can be used to accumulate the length without constructing a shorter list. See the answer of #WuXingbo - his answer is incorrect, but once you realize that length is not needed at all with his approach, it should be easy for you to come with correct solution.
Somewhat contradictory to common sense, in a lazy language foldr is faster and uses less memory than foldl. You should ask your teacher why.
I would rewrite foo as
foo :: Char -> [(String, Int)] -> Int
foo c = length . filter ((==c).head.fst)
fst fetches the first element of a two-element tuple.
(==c) is a one-argument function that compares its input with c (see http://www.haskell.org/tutorial/functions.html paragraph 3.2.1 for better explanation).

Resources