Having trouble with H-15 - haskell

I am doing Problem 15. Which states:
(**) Replicate the elements of a list a given number of times.
Example:
* (repli '(a b c) 3)
(A A A B B B C C C)
Example in Haskell:
> repli "abc" 3
"aaabbbccc"
My plan was to do something like this:
repli :: [a] -> Integer -> [a]
repli [] y = []
repli (x:xs) y | appendNo x y == [] = repli(xs) y
| otherwise = appendNo x y : (x:xs)
where
appendNo :: a -> Integer -> [a]
appendNo a 0 = []
appendNo a y = a:appendNo a (y-1)
Where I would make a function called appendNo that returns a list of 1 element y times then append it to the original list. Then take the body of the list and repeat this process until there are no more body elements left. But, I get the error:
H15.hs:6:30:
Couldn't match type `a' with `[a]'
`a' is a rigid type variable bound by
the type signature for repli :: [a] -> Integer -> [a] at H15.hs:3:1
In the return type of a call of `appendNo'
In the first argument of `(:)', namely `appendNo x y'
In the expression: appendNo x y : (x : xs)
Failed, modules loaded: none.
6:30 is at the on the p in appendNo in this line:
| otherwise = appendNo x y : (x:xs)
Ok thanks dave4420 I was able to figure it out by doing:
repli :: [a] -> Integer -> [a]
repli [] y = []
repli (x:xs) y = appendNo x y ++ repli(xs) y
where
appendNo :: a -> Integer -> [a]
appendNo a 0 = []
appendNo a y = a:appendNo a (y-1)

| otherwise = appendNo x y : (x:xs)
There is a type error in this line. So ask yourself:
What is the type of appendNo x y?
What is the type of (x:xs)?
What is the type of (:)?
Then you should be able to see why they don't match up.
If you still can't see why they don't match up, ask yourself
What is the type of x?
What is the type of xs?
What is the type of (:)?
Bear in mind that this time the types do match up.

As the problem is solved, let me give you a hint: You should try to think in transformations, not in "loops". Start with some concrete values like n = 3 and list = "ABCD". Then you should think along the lines "I need every element three times". There is already a function for doing the replication, which is surprisingly called replicate. So the sentence can be translated to map (replicate 3) "ABCD", which gives you ["AAA","BBB","CCC","DDD"]. That's almost what you want, you just need to concat the elements. This gives:
repli list n = concat (map (replicate n) list)
Because this operation is very common, there is a concatMap function combining concat and map, as well as the operator (>>=) doing the same, just with flipped arguments. So a very short solution would be:
repli list n = list >>= replicate n
This can be translated to the do-notation or a list comprehension as well:
repli list n = do
x <- list
y <- replicate n x
return y
repli list n = [y | x <- list, y <- replicate n x]

Related

Haskell: for every even appearance in an array, concatenate an int to the final list

I'm currently trying to write a function that takes as arguments an Int and an array of Ints and for every even value in the array, it concatenates the Int to the final array.
So, something like this:
f 3 [1,2,3,4,5,6] = [1,2,3,3,4,3,5,6,3]
This is the code I imagined would work (I'm just beginning so sorry if it's bad):
f :: Int -> [Int] -> [Int]
f(x,[]) = []
f(x,y)
|even head(y) = (head(y) ++ [x] ++ f(x,drop 1 y)
|otherwise = head(y) ++ f(x,(drop 1 y))
The error I'm getting is "Couldn't match expected type of 'Int' with actual type (a3, [[a3]])'. I understand the parameters types are mismatched, but I'm not sure how a proper syntax would look like here
You use (x, []), so that means the input type would be a tuple, so f :: (Int, [Int]) -> [Int].
I would also use pattern matching instead of head and tail, so:
f :: Int -> [Int] -> [Int]
f _ [] = []
f x (y:ys)
| even y = y : x : f x ys
| otherwise = y : f x ys
You can also generalize the type signature, and work with an inner function to avoid passing the x each time:
f :: Integral a => a -> [a] -> [a]
f x = go
where go [] = []
go (y:ys)
| even y = y : x : go ys
| otherwise = y : go ys
Another way of looking at this would be using a right fold to insert the desired element after even numbers.
f :: Int -> [Int] -> [Int]
f x lst = foldr (\y i -> if even y then y:x:i else y:i) [] lst
Which we can simplify to:
f :: Int -> [Int] -> [Int]
f x = foldr (\y i -> if even y then y:x:i else y:i) []
Note that without specifying the type, the more general inferred type of f would be:
f :: (Foldable t, Integral a) => a -> t a -> [a]

Haskell: cannot construct the infinite type

I got a list of tuples (day:month) and want to find the month with the biggest amount of days.
I made a function that accepts my list of tuples and list of months (or just 1) to check and returns the maximum amount of dates in one month in specified period
maxweekends x [] = 0
maxweekends x [n] = length (filter ((==n).snd) x)
maxweekends x (y:ys) = max (maxweekends x [y]) (maxweekends x ys)
Then I wrote some simple function to use it, but I cant compile it because of "cannot construct the infinite type" error. I already spent a few hours with this error but I just cant understand what is wrong.
func x [] = 0
func x (y:ys)
| maxweekends x y < maxweekends x ys = func x ys
| otherwise = y
In theory it should call itself until there is no month with bigger amount of dates and then just return answer.
Thanks.
Edit: here is traceback of error
Your infinite type arises from the fact that you call maxweekends with x y and x ys. Since the type of maxweekends :: Eq b => [(a, b)] -> [b] -> Int specifies that given the "second" parameter is of type [b], then the first parameter is a type of [(a, b)], this means that x should be [(a, b)] (for the first call) and [(a, [b])] (for the second call) at the same time, which is impossible.
I think it might be better to first restructure this. Let us first construct a function that looks like:
groupLength :: Eq b => Int -> b -> [(a, b)] -> Int
groupLength d _ [] = d
groupLength _ x ys = length (filter ((x==) . snd) ys)
This will thus for a given "month" x obtain the number of elements in the list with as second item of the tuple that "month".
Now we can generate an "argmax" that calculates for which x, f x produces a maximum value:
argmax :: Ord b => (a -> b) -> [a] -> Maybe (a, b)
argmax _ [] = Nothing
argmax f (x:xs) = Just (go x (f x) xs)
where go x y [] = (x, y)
go x y (x2:xs) | y <= y2 = go x y xs
| otherwise = go x2 y2 xs
where y2 = f x2
So now it is only a matter of combining the the groupLength (which is an abstract version of your maxweekends with argmax (which is more or less what your func is after). I leave this as an exercise.

How to apply a function to a specific element of a list

How can I apply a function to only a single element of a list?
Any suggestion?
Example:
let list = [1,2,3,4,3,6]
function x = x * 2
in ...
I want to apply function only to the first occurance of 3 and stop there.
Output:
List = [1,2,6,4,3,6] -- [1, 2, function 3, 4, 3, 6]
To map or not to map, that is the question.
Better not to map.
Why? Because map id == id anyway, and you only want to map through one element, the first one found to be equal to the argument given.
Thus, split the list in two, change the found element, and glue them all back together. Simple.
See: span :: (a -> Bool) -> [a] -> ([a], [a]).
Write: revappend (xs :: [a]) (ys :: [a]) == append (reverse xs) ys, only efficient.
Or fuse all the pieces together into one function. You can code it directly with manual recursion, or using foldr. Remember,
map f xs = foldr (\x r -> f x : r) [] xs
takeWhile p xs = foldr (\x r -> if p x then x : r else []) [] xs
takeUntil p xs = foldr (\x r -> if p x then [x] else x : r) [] xs
filter p xs = foldr (\x r -> if p x then x : r else r) [] xs
duplicate xs = foldr (\x r -> x : x : r) [] xs
mapFirstThat p f xs = -- ... your function
etc. Although, foldr won't be a direct fit, as you need the combining function of the (\x xs r -> ...) variety. That is known as paramorphism, and can be faked by feeding tails xs to the foldr, instead.
you need to maintain some type of state to indicate the first instance of the value, since map will apply the function to all values.
Perhaps something like this
map (\(b,x) -> if (b) then f x else x) $ markFirst 3 [1,2,3,4,3,6]
and
markFirst :: a -> [a] -> [(Boolean,a)]
markFirst a [] = []
markFirst a (x:xs) | x==a = (True,x): zip (repeat False) xs
| otherwise = (False,x): markFirst a xs
I'm sure there is an easier way, but that's the best I came up with at this time on the day before Thanksgiving.
Here is another approach based on the comment below
> let leftap f (x,y) = f x ++ y
leftap (map (\x -> if(x==3) then f x else x)) $ splitAt 3 [1,2,3,4,3,6]
You can just create a simple function which multiples a number by two:
times_two :: (Num a) => a -> a
times_two x = x * 2
Then simply search for the specified element in the list, and apply times_two to it. Something like this could work:
map_one_element :: (Eq a, Num a) => a -> (a -> a) -> [a] -> [a]
-- base case
map_one_element _ _ [] = []
-- recursive case
map_one_element x f (y:ys)
-- ff element is found, apply f to it and add rest of the list normally
| x == y = f y : ys
-- first occurence hasnt been found, keep recursing
| otherwise = y : map_one_element x f ys
Which works as follows:
*Main> map_one_element 3 times_two [1,2,3,4,3,6]
[1,2,6,4,3,6]

basic Haskell: defining sorting function by recursion

So I have slight problem with sorting function. I need to define (using recursion) a function i, that takes as an argument a list of arguments a (this list needs to belong to Ord), which outputs ordered list of elements of type a.
Example:
i [3,2,1] = [1,2,3]
I have managed to come with this solution:
i :: Ord a => [a] -> [a]
i [] = []
i (x:xs)
| x <= head (xs) = x: i xs
| otherwise = i xs : x
But it doesn't compute, outputting many errors. What is wrong?
Let me give you some hints to get you started. First of all, let's fix the formatting:
i :: Ord a => [a] -> [a]
i [] = []
i (x:xs)
| x <= head (xs) = x: i xs
| otherwise = i xs : x
This throws an error which says:
In the first argument of ā€˜(:)ā€™, namely ā€˜i xsā€™
In the expression: i xs : x
Now, this expression i xs : x is problematic. The type of (:) is (:) :: a -> [a] -> [a]. But in your expression you are passing a list instead of a value. What you meant to use was possibly ++. Using that fixes the compile error:
i :: Ord a => [a] -> [a]
i [] = []
i (x:xs)
| x <= head (xs) = x: i xs
| otherwise = i xs ++ [x]
Now, if you try it in ghci, you will get a runtime exception:
ghci> i [3,2,1]
*** Exception: Prelude.head: empty list
Can you guess why ? That's because you haven't handled the case where the list is of length 1. So handling the case will give you this:
i :: Ord a => [a] -> [a]
i [] = []
i (x:[]) = [x]
i (x:xs)
| x <= head (xs) = x: i xs
| otherwise = i xs ++ [x]
Now, you may think that this works:
ghci> i [3,2,1]
[1,2,3]
ghci> i [3,1,2]
[1,2,3]
But it doesn't actually work, because there is a flaw in your algorithm. Just comparing the first two elements of the list won't give you an sorted array.
ghci> i [2,1,3]
[1,3,2]
I hope this is enough to get you started.

Get positions of elements in list of strings in Haskell

my title might be a bit off and i'll try to explain a bit better what i'm trying to achieve.
Basically let's say i have a list:
["1234x4","253x4",2839",2845"]
Now i'd like to add all the positions of the strings which contain element 5 to a new list. On a current example the result list would be:
[1,3]
For that i've done similar function for elem:
myElem [] _ = False
myElem [x] number =
if (firstCheck x) then if digitToInt(x) == number then True else False else False
myElem (x:xs) number =
if (firstCheck x) then (if digitToInt(x) == number then True else myElem xs number) else myElem xs number
where firstCheck x checks that the checked element isn't 'x' or '#'
Now in my current function i get the first element position which contains the element, however my head is stuck around on how to get the full list:
findBlock (x:xs) number arv =
if myElem x number then arv else findBlock xs number arv+1
Where arv is 0 and number is the number i'm looking for.
For example on input:
findBlock ["1234x4","253x4",2839",2845"] 5 0
The result would be 1
Any help would be appreciated.
The function you want already exists in the Data.List module, by the name of findIndices. You can simply use (elem '5') as the predicate.
http://hackage.haskell.org/package/base-4.8.1.0/docs/Data-List.html#v:findIndices
If, for some reason, you're not allowed to use the built-in one, it comes with a very pretty definition (although the one actually used has a more complicated, more efficient one):
findIndices p xs = [ i | (x,i) <- zip xs [0..], p x]
By the way, I found this function by searching Hoogle for the type [a] -> (a -> Bool) -> [Int], which (modulo parameter ordering) is obviously the type such a function must have. The best way to find out of Haskell has something is to think about the type it would need to have and search Hoogle or Hayoo for the type. Hoogle is better IMO because it does slightly fuzzy matching on the type; e.g. Hayoo wouldn't find the function here by the type I've given, because it take the arguments in the reverse order.
An implementation of findIndices, for instructional purposes:
findIndices ok list = f list 0 where
f [] _ = []
f (x:xs) ix
| ok x = ix : f xs (ix+1)
| otherwise = f xs (ix+1)
Use it like findIndices (elem '5') my_list_o_strings
You're trying to work your way through a list, keeping track of where you are in the list. The simplest function for doing this is
mapWithIndex :: (Int -> a -> b) -> [a] -> [b]
mapWithIndex = mwi 0 where
mwi i _f [] = i `seq` []
mwi i f (x:xs) = i `seq` f i x : mwi (i+1) f xs
This takes a function and a list, and applies the function to each index and element. So
mapWithIndex (\i x -> (i, x)) ['a', 'b', 'c'] =
[(0,'a'), (1,'b'),(2,'c')]
Once you've done that, you can filter the list to get just the pairs you want:
filter (elem '5' . snd)
and then map fst over it to get the list of indices.
A more integrated approach is to use foldrWithIndex.
foldrWithIndex :: (Int -> a -> b -> b) -> b -> [a] -> b
foldrWithIndex = fis 0 where
fis i _c n [] = i `seq` n
fis i c n (x:xs) = i `seq` c i x (fis (i+1) c n xs)
This lets you do everything in one step.
It turns out that you can implement foldrWithIndex using foldr pretty neatly, which makes it available for any Foldable container:
foldrWithIndex :: (Foldable f, Integral i) =>
(i -> a -> b -> b) -> b -> f a -> b
foldrWithIndex c n xs = foldr go (`seq` n) xs 0 where
go x r i = i `seq` c i x (r (i + 1))
Anyway,
findIndices p = foldrWithIndex go [] where
go i x r | p x = i : r
| otherwise = r

Resources