Related
I have this list of tuples
[(4,'a'), (1,'b'), (2,'c'), (2,'a'), (1,'d'), (4,'e')]
I want to get the first elements of every tuple then replicate it to make the following: "aaaabccaadeeee"
I came up with this code, but it only gives me the replicate of the first tuple.
replicate (fst ( head [(4,'a'), (1,'b')])) ( snd ( head [(4,'a'), (1,'b')]))
--output is: "aaaa"
I was thinking to use map for to get the replicate of every tuple, but I didn't succeed.
Since you already know how to find the correct answer for a single element, all you need is a little recursion
func :: [(Int, a)] -> [a]
func [] = []
func ((n, elem):rest) = (replicate n elem) ++ (func rest)
Mapping the values should also work. You just need to concatenate the resulting strings into one.
func :: [(Int, a)] -> [a]
func xs = concat $ map func2 xs where
func2 (n, elem) = replicate n elem
Or, if you are familiar with currying:
func :: [(Int, a)] -> [a]
func xs = concat $ map (uncurry replicate) xs
Finally, if you are comfortable using function composition, the definition becomes:
func :: [(Int, a)] -> [a]
func = concat . map (uncurry replicate)
Using concat and map is so common, there is a function to do just that. It's concatMap.
func :: [(Int, a)] -> [a]
func = concatMap (uncurry replicate)
Let
ls = [(4,'a'), (1,'b'), (2,'c'), (2,'a'), (1,'d'), (4,'e')]
in
concat [replicate i x | (i, x) <- ls]
will give
"aaaabccaadeeee"
The point-free version
concat . map (uncurry replicate)
You are correct about trying to use map. But first lets see why your code did not work
replicate (fst ( head [(4,'a'), (1,'b')])) ( snd ( head [(4,'a'), (1,'b')]))
Your first parameter to replicate is the head of your list which is (4, 'a'). Then you are calling fst on this, thus the first parameter is 4. Same things happens with second parameter and you get 'a'. The result of which you see.
Before using map lets try to do this with recursion. You want to take one element of list and apply replicate to it and then combine it with the result of applying replicate on the second element.
generate [] = []
generate (x:xs) = replicate (fst x) (snd x) ++ generate xs
Do note I am using pattern matching to get the first element of list. You can us the pattern matching to get the element inside the tuple as well, and then you would not need to use the fst/snd functions. Also note I am using pattern matching to define the base case of empty list.
generate [] = []
generate ((x,y):xs) = replicate x y ++ generate xs
Now coming to map, so map will apply your function to every element of the list, here's the first try
generate (x,y) = replicate x y
map generate xs
The result of the above will be slightly different from recursion. Think about it, map is going to apply generate to every element and store the result in a list. generate creates a list. So when you apply map you are creating a list of list. You can use concat to flatten it if you want, which will give you the same result as recursion.
Last thing, if you can use recursion, then you can use fold as well. Fold will just apply a function to every element of the list and return the accumulated results (broadly speaking).
--first parameter is the function to apply, second is the accumulator, third is your list
foldr step [] xs
where step (x,y) acc =
(replicate x y) ++ acc
Again here I have used pattern matching in the function step to extract the elements of the tuple out.
I want to do a Haskell function where the input (a list of Strings) is ordered (always. input is valid only if is ordered) and I want to get the number of occurrences of each different string.
Example:
ContaOcs["a", "a", "b", "c", "c", "c", "d"]
Should return:
[(2,"a"), (1,"b"), (3,"c"), (1,"d")]
Here is What I'm trying to do:
module Main where
contaOcs :: [String] -> [(Int, String)]
contaOcs [] = [_,_]
contaOcs [x] = [1,x]
contaOcs (i, x1:x2:xs)
| x1 == x2 = (i+1,(x2:xs))
| otherwise = (0, (x2:xs))
But this code have some errors and I'm not so sure how I should do to accomplish this
I'm new to functional programing and Haskell. Can anyone help me with some information?
Thanks for any help.
There are some syntactical problems as well as problems with the types. The first line looks like:
contaOcs [] = [_,_]
But an underscore (_) in the result does not makes any sense, you can only construct lists with values in it. When we count the number of occurences of an empty list, the result will be an empty list, so contaOcs [] = [].
As for the second:
contaOcs [x] = [1,x]
Here you aim to return a list with two elements: a 1 and an x (which is a String). In Haskell the elements of a list all have the same type. What you can do is return a list of 2-tuples with the first item an Int, and the second a String, like the signature suggests, but then you need to wrap the values in a 2-tuple, like contaOcs [x] = [(1,x)].
In your last clause, you write:
contaOcs (i, x1:x2:xs) = ...
which does not make much sense: the input type is a list (here of Strings), not a 2-tuple with an Int, and a list of strings.
So the input will look like:
contaOcs (x1:x2:xs) = ...
The output, like (i+1,(x2:xs)) also is not in "harmony" with the proposed output type in the signature, this looks like a 2-tuple with an Int, and a list of Strings, so (Int, [String]), not [(Int, String)].
Based on the above comments, we have derived something like:
contaOcs :: [String] -> [(Int, String)]
contaOcs [] = []
contaOcs [x] = [(1,x)]
contaOcs (x1:x2:xs)
| x1 == x2 = -- ...
| otherwise = -- ...
So now there are two parts to fill in. In case x1 and x2 are not equal, that means that we can first yield a tuple (1, x1) in the list, followed by the result of contaOcs on the rest of the list (x2 included), so:
(1, x1) : contaOcs (x2:xs)
In the latter case, it means that we first make a recursive call to contaOcs with (x2:xs), and then increment the counter of the first item of that list. We are sure such element exists, since we make a recursive call with a list containing at least one element, and by induction, that means the result contains at least one element as well, since the base case contains one element, and the recursive case either prepends elements to the result, or updates these.
So we can use a pattern guard, and maniplate the result, like:
contaOcs :: [String] -> [(Int, String)]
contaOcs [] = []
contaOcs [x] = [(1,x)]
contaOcs (x1:x2:xs)
| x1 == x2, ((yi, yv):ys) <- contaOcs (x2:xs) = (yi+1, yv) : ys
| otherwise = (1, x1) : contaOcs (x2:xs)
We can also use an "as-pattern": we only need a reference to the tail of the list starting with x2, not xs:
contaOcs :: [String] -> [(Int, String)]
contaOcs [] = []
contaOcs [x] = [(1,x)]
contaOcs (x1:xs#(x2:_))
| x1 == x2, ((yi, yv):ys) <- contaOcs xs = (yi+1, yv) : ys
| otherwise = (1, x1) : contaOcs xs
The above is however not very elegantly. It might be better to use an accumulator here, I leave this as an exercise.
Let's look at some of the errors mentioned by ghc. Always pay close attention to when GHC talks about Expected and Actual types, as these messages are always illuminating. Expected indicates what GHC thinks you should write. Actual indicates what you wrote. You either need to change what you wrote (read: change your code), or change what GHC thinks you should write (read: change your type annotations). In this case it's mostly the former.
hw.hs:2:16: error:
• Found hole: _ :: (Int, String)
• In the expression: _
In the expression: [_, _]
In an equation for ‘contaOcs’: contaOcs [] = [_, _]
• Relevant bindings include
contaOcs :: [String] -> [(Int, String)] (bound at hw.hs:2:1)
|
2 | contaOcs [] = [_,_]
| ^
hw.hs:2:18: error:
• Found hole: _ :: (Int, String)
• In the expression: _
In the expression: [_, _]
In an equation for ‘contaOcs’: contaOcs [] = [_, _]
• Relevant bindings include
contaOcs :: [String] -> [(Int, String)] (bound at hw.hs:2:1)
|
2 | contaOcs [] = [_,_]
| ^
The underscore is used as a placeholder (or "hole"), to be filled in later. GHC is telling you that you should figure out something to put in these holes.
hw.hs:3:19: error:
• Couldn't match type ‘[Char]’ with ‘(Int, String)’
Expected type: (Int, String)
Actual type: String
• In the expression: x
In the expression: [1, x]
In an equation for ‘contaOcs’: contaOcs [x] = [1, x]
|
3 | contaOcs [x] = [1,x]
|
You have declared that the return type of the function is [(Int, String)], in other words, a List, where each element of the list is a Tuple of Int and String.
Therefore, each element in the list should be a Tuple. The syntax [1,x] means a list with two elements: 1 and x. GHC has noticed that x, however, is known to be a String, which is not a Tuple. (GHC failed to notice that 1 is not a tuple, for... reasons. Numbers in Haskell are a little weird and GHC is not so helpful with those.)
Perhaps you meant to write (1, x), which is a tuple of 1 (an Int) and x (a String). However, don't forget to also put that tuple into a list somehow, since your return type is a list of tuples.
hw.hs:4:10: error:
• Couldn't match expected type ‘[String]’
with actual type ‘(Integer, [a0])’
• In the pattern: (i, x1 : x2 : xs)
In an equation for ‘contaOcs’:
contaOcs (i, x1 : x2 : xs)
| x1 == x2 = (i + 1, (x2 : xs))
| otherwise = (0, (x2 : xs))
|
4 | contaOcs (i, x1:x2:xs)
| ^^^^^^^^^^^^^
GHC is again reminding you that it expects a list of tuples, but in this case, you gave it just one tuple.
The errors are mostly the same as this.
contaOcs :: [String] -> [(Int, String)]
contaOcs consumes a list of strings: xss, for each unique string: xs in xss, we produce a pair: p, whose first element represents the number of occurrences of xs in xss, and the second element of p is that xs itself.
We know we need to group strings by their uniqueness and count each unique string's total occurrences. You can follow this idea and implement the rest yourself. contaOcs takes a list and produces a new list so list comprehension should give you what you want. You're transforming one list to another, so fmap a function that accumulates should work. You can also just use natural recursion or accumulator. Here is one way to write contaOcs:
contaOcs = (return . liftA2 (,) length head =<<) . group
Write down the signature, purpose statement, some sample data and test cases first, then it's just a matter of finding the solutions that best fit your need.
This is a good example of when a co-recursive function is helpful.
contaOcs :: [String] -> [(Int, String)]
We'll define contaOcs as the outer function that takes the list of strings and returns the tuples. First let's look at the trivial cases:
contaOcs [] = []
contaOcs [x] = [(1,x)]
Pass an empty list, and you should get back an empty list. Pass a single element list, and you should get back a list with one element: (1, x). Now we can guarantee that any other list is 2+ elements long.
contaOcs (x:xs) = go x xs
go? What is go you might ask? Well let's define it in the where clause:
where
go cur xs = let (this, rest) = span (==x) xs
in (succ . length $ this, cur) : contaOcs diff
That's kind of a lot, so let's unpack. go is an idiomatic term for a function helper (this could as easily be named f or frobnicator, it doesn't matter). It takes the character we're counting, which is split separately from the rest of its list, and calls it x. It runs a span (==x) against the rest of the list, which splits it into a tuple (longestPrefixThatMatches, rest). We return the length of that longest prefix (plus one, since we've stripped off the front character) paired with the character itself in a tuple, then cons that with the recursive case -- handing the rest of the list back to the outer function to handle.
What you want can be done by a one-liner
Prelude> import Data.List
Prelude Data.List> ls = ["a", "a", "b", "c", "c", "c", "d"]
Prelude Data.List> [(length x, head x) | x <- group ls]
[(2,"a"),(1,"b"),(3,"c"),(1,"d")]
I mix list comprehension with the group function. Basic concepts you can make yourselves familiar with.
contaOcs :: [String] -> [(Int, String)]
contaOcs xs = foldr foldContaOcs [] xs
where foldContaOcs s [] = (1, s):[]
foldContaOcs s ((n, ch):xs) = if ch == s then (n + 1, s) : xs
else (1, s): (n, ch): xs
I have been working with Haskell for a little over a week now so I am practicing some functions that might be useful for something. I want to compare two lists recursively. When the first list appears in the second list, I simply want to return the index at where the list starts to match. The index would begin at 0. Here is an example of what I want to execute for clarification:
subList [1,2,3] [4,4,1,2,3,5,6]
the result should be 2
I have attempted to code it:
subList :: [a] -> [a] -> a
subList [] = []
subList (x:xs) = x + 1 (subList xs)
subList xs = [ y:zs | (y,ys) <- select xs, zs <- subList ys]
where select [] = []
select (x:xs) = x
I am receiving an "error on input" and I cannot figure out why my syntax is not working. Any suggestions?
Let's first look at the function signature. You want to take in two lists whose contents can be compared for equality and return an index like so
subList :: Eq a => [a] -> [a] -> Int
So now we go through pattern matching on the arguments. First off, when the second list is empty then there is nothing we can do, so we'll return -1 as an error condition
subList _ [] = -1
Then we look at the recursive step
subList as xxs#(x:xs)
| all (uncurry (==)) $ zip as xxs = 0
| otherwise = 1 + subList as xs
You should be familiar with the guard syntax I've used, although you may not be familiar with the # syntax. Essentially it means that xxs is just a sub-in for if we had used (x:xs).
You may not be familiar with all, uncurry, and possibly zip so let me elaborate on those more. zip has the function signature zip :: [a] -> [b] -> [(a,b)], so it takes two lists and pairs up their elements (and if one list is longer than the other, it just chops off the excess). uncurry is weird so lets just look at (uncurry (==)), its signature is (uncurry (==)) :: Eq a => (a, a) -> Bool, it essentially checks if both the first and second element in the pair are equal. Finally, all will walk over the list and see if the first and second of each pair is equal and return true if that is the case.
Currently working with Haskell on a function that takes a String in parameters and return a list of (Char, Int) The function occur works with multiple type and is used in the function called word.
occur::Eq a=>a->[a]->Int
occur n [] = 0
occur n (x:xs) = if n == x
then 1 + occur n xs
else occur n xs
word::String->[(String,Int)]
word xs = [(x,y) | x<-head xs, y<-(occur x xs)]
Get me this error
ERROR "file.hs":31 - Type error in generator
*** Term : head xs
*** Type : Char
*** Does not match : [a]
What am I doing wrong ? How can I make this code run properly , type-wise ?
The problem is you say that xs has type String, so head xs has type Char, and then you try to iterate over a single Char, which can't be done. The a <- b syntax only works when b is a list. You have the same problem in that y <- occur x xs is trying to iterate over a single Int, not a list of Int. You also had a problem in your type signature, the first type in the tuple should be Char, not String. You can fix it with:
word :: String -> [(Char, Int)]
word xs = [(x, occur x xs) | x <- xs]
Here we loop over the entire string xs, and for each character x in xs we compute occur x xs.
I would actually recommend using a slightly stronger constraint than just Eq. If you generalize word (that I've renamed to occurrences) and constrain it with Ord, you can use group and sort, which allow you to keep from iterating over the list repeatedly for each character and avoid the O(n^2) complexity. You can also simplify the definition pretty significantly:
import Control.Arrow
import Data.List
occurrences :: Ord a => [a] -> [(a, Int)]
occurrences = map (head &&& length) . group . sort
What this does is first sort your list, then group by identical elements. So "Hello, world" turns into
> sort "Hello, world"
" ,Hdellloorw"
> group $ sort "Hello, world"
[" ", ",", "H", "d", "e", "lll", "oo", "r", "w"]
Then we use the arrow operator &&& which takes two functions, applies a single input to both, then return the results as a tuple. So head &&& length is the same as saying
\x -> (head x, length x)
and we map this over our sorted, grouped list:
> map (head &&& length) $ group $ sort "Hello, world"
[(' ',1),(',',1),('H',1),('d',1),('e',1),('l',3),('o',2),('r',1),('w',1)]
This eliminates repeats, you aren't having to scan the list over and over counting the number of elements, and it can be defined in a single line in the pointfree style, which is nice. However, it does not preserve order. If you need to preserve order, I would then use sortBy and the handy function comparing from Data.Ord (but we lose a nice point free form):
import Control.Arrow
import Data.List
import Data.Ord (comparing)
occurrences :: Ord a => [a] -> [(a, Int)]
occurrences = map (head &&& length) . group . sort
occurrences' :: Ord a => [a] -> [(a, Int)]
occurrences' xs = sortBy (comparing ((`elemIndex` xs) . fst)) $ occurrences xs
You can almost read this as plain English. This sorts by comparing the index in xs of the first element of the tuples in occurrences xs. Even though elemIndex returns a value of type Maybe Int, we can still compare those directly (Nothing is "less than" any Just value). It simply looks up the first index of each letter in the original string and sorts by that index. That way
> occurrences' "Hello, world"
returns
[('H',1),('e',1),('l',3),('o',2),(',',1),(' ',1),('w',1),('r',1),('d',1)]
with all the letters in the original order, up to repetition.
Problem
i have list of int as [123,123] which i required to be as [1,2,3,1,2,3]
Current Code
i tried out the following code using recursion
fat::[Int]->[Int]
fat [] = []
fat (a,b,c:xs) = a : b : c : fat xs
Conclusions
i have no idea how to acess values as '1' , '2 , '3 in a list [123,123] separetly
I suggest to use the digs function given in this answer on each element of your list. It splits an Int into a list of digits ([Int]). Then you just need to concatenate the resulting lists. This 'map and concatenate results' requirement is a perfect job for concatMap
fat :: [Int] -> [Int]
fat = concatMap digs
This gives:
*Main> fat [123,123]
[1,2,3,1,2,3]
Which is what you want, if I understood correctly.
splitNum :: Int -> [Int]
splitNum n | n <= 9 = [n]
| otherwise = (splitNum (n `div` 10)) ++ [n `mod` 10]
fat :: [Int] -> [Int]
fat x = concatMap splitNum x
splitNum is used to convert an Int to a [Int] by splitting it into the division by ten reminders and appending the resulting Int to the splitted rest (recursion!)
Now, having a function that converts numbers into lists, go through input, apply splitNum to any Number in the inner list and concat all resulting lists (list comprehension!)
As a new Haskell programmer I will give you my thoughts of this problem. Just because I think it's good to have many alternatives, especially from different people with different experience.
Here's my take on the problem:
For each item in the list, convert that item to a char list using read.
Send that char list into a function which converts each item of that list into an int, then return an list of ints.
Concat that list of ints into the main list.
To clarify:
[123, 234]
123 turns into ['1', '2', '3']
['1', '2', '3'] turns into [1, 2, 3]
[1, 2, 3] gets concat in the main list
the cycle repeats for 234.
The util function would look something like this:
import Char
charsToInts :: [Char] -> [Int]
charsToInts [] = []
charsToInts (x:xs) = digitToInt x : charsToInts xs
Coming from a imperative background that's how I would have solved it. Probably slower than just splitting the number mathematically, but I thought it would be interesting to show a alternative.
To pinpoint the problem bluntly, you have no idea how to access the digits separately because you do not understand Haskell types and pattern matching. Let me try to help dispel some of your misconceptions.
Let's look at your list:
[123, 123]
What is its type? It is clearly a list of ints, or [Int]. With lists, you can pattern match on the constructor :, known to lispers as "cons", or "list constructor". You put a single element on the left side of the :, and another list on the right side. The list on the right side can be the empty list [], which basically indicates the end of the list. Haskell provides "syntactic sugar" to make lists easier to write, but [123,456] actually gets desugared into 123:(456:[]). So when you pattern match (x:y:z), you can now see that x will be assigned 123 and y will be assigned 456. z will be the rest of the list after x and y; in this case only [] is left.
Now then, pattern matching with : works for lists. Ints are not lists, so you can't use : to pattern match on the digits of an Int. However, Strings are lists, because String is the same as [Char]. So if you turn your Int into a String then you can pattern match on each character.
map show [123, 123]
map applies a function to all elements of a list. show can take an Int and turn it into a String. So we map show over the list of Ints to get a list of Strings.
["123", "123"]
Now let's turn those Strings into lists of Ints. Since String is simply [Char], we will again make use of map.
map digitToInt "123" -- this requires that you import Data.Char (digitToInt)
This will give us [1,2,3]; each Char in the list is turned into an Int. This is what we want to do to each String in our list ["123", "123"]. We want to map digitToInt to each String. But we have a list of Strings. So what do we do? We map it!
map (map digitToInt) ["123", "123"]
This will give us [[1,2,3], [1,2,3]]. Almost what we wanted. Now we just have to flatten the list of list of Ints ([[Int]]) into just a list of Int ([Int]). How can we do that? Stop...Hoogle time! Hoogling [[a]] -> [a] we find the very first hit, concat, is exactly what we wanted.
Let's put it all together. First we do map show to get from [Int] to [String]. Then we do map (map digitToInt) to get from [String] to [[Int]]. Then we do concat to get from [[Int]] to [Int]. Then we'll just print it out!
import Data.Char (digitToInt)
main = print $ concat $ map (map digitToInt) $ map show $ [123, 123]
Now let's pull most of that out into a function fat
import Data.Char (digitToInt)
main = print $ fat [123, 123]
fat :: [Int] -> [Int]
fat xs = concat $ map (map digitToInt) $ map show $ xs
From here you could make it prettier in a few different ways. concat $ map is the same as concatMap, and since we map both (map digitToInt) and show in sequence, we can merge those. Also making it pointfree, we can end up with quite a terse definition:
fat = concatMap (map digitToInt . show)
For the sake of completeness, I wrote it as suggested by #Ancide
Implementation
fat' :: [Int] -> [Int]
fat' l = map (read) [[z] | z <- [x | k <- (map (show) l), x <- k]]
Explanation:
{- last result -} stands for the result of the last code explained.
map (show) l
This takes every element inside l and converts it to [String].
[x | k <- {- last result -}, x <- k]
While k goes through all elements inside the last result, x enumerates all character in each k. All those are added to a list. Now you have a String, respectively a [Char] with all digits next to each others.
[[z] | z <- {- last result -}]
This part takes each Char from the String and puts it into an empty String. Notice the [z] part! This make a list around z, which is (see above) the same as String. Now you have a list of String with a String for each digit.
map (read) {- last result -}
This takes every item in the last result and converts it back to Int and joins them to [Int]. Now you have a list of type [Int] of the wanted result.
Resumé
Although this implementation is possible, it's neither fast, due to all the type conversions, nor readable.
Playing around with the list monad I came up with this. Pretty much the same #Ankur's solution, except using the list monad:
fat :: [Int] -> [Int]
fat is = is >>= show >>= return . digitToInt
If you had two numbers, a and b then you could turn them into a single number by doing 10*a + b. The same principles apply for three.
It sounds like one way of doing this would be to splitEvery into lumps of three and then map a function to turn a list of three into a single number.
Does that help?
You need a function to convert Integer to string... which is obviously Show function
Another function to convert a Char to Integer which is "digitToInt" in module Char
And here we go :
fat::[Int]->[Int]
fat [] = []
fat ls = concat $ map (map digitToInt) (map show ls)
Please let me know if it works :)