Haskell, type matching problems - haskell

I cannot understand why the function:
repli :: [a] -> Int -> [a]
repli xs n = concatMap (replicate n) xs
cannot be rewritten as:
repli :: [a] -> Int -> [a]
repli [] _ = []
repli (x:xs) n = (take n $ repeat x) : repli xs n
or
repli :: [a] -> Int -> [a]
repli [] _ = []
repli (x:xs) n = (replicate n x) : repli xs n
Ghci complains:
Couldn't match expected type ‘a’ with actual type ‘[a]’
‘a’ is a rigid type variable bound by
the type signature for repli :: [a] -> Int -> [a]
at 99questions.hs:41:10
Relevant bindings include
xs :: [a] (bound at 99questions.hs:43:10)
x :: a (bound at 99questions.hs:43:8)
repli :: [a] -> Int -> [a] (bound at 99questions.hs:42:1)
In the first argument of ‘(:)’, namely ‘(replicate n x)’
In the expression: (replicate n x) : repli xs n
I don't understand why, since doing all the type computations it turns out ok. repeat x is [a] and so take n is [a]. Therefore it shouldn't complain.

The signature of (:) is a -> [a] -> [a]. Therefore, you cannot have lists on both sides of the operator. That's the cause of your error.
You could instead use (++), which has the signature [a] -> [a] -> [a].

Related

Types and higher-order function in Haskell

Could someone help me to understand this issue.
I have this simple function:
takeAsLong :: [a] -> (a -> Bool) -> [a]
takeAsLong [] _ = []
takeAsLong (x:xs) test | test x = x : takeAsLong xs test
| otherwise = []
But when I try to rewrite it using if-then-else I have an error.
takeAsLong :: [a] -> (a -> Bool) -> [a]
takeAsLong [] _ = []
takeAsLong (x:xs) test = if test x then x : takeAsLong [xs] test else []
The error is in the recursive call of "takeAsLong [xs] test" but I dont understand why it doesnt like it?
Error msg:
Couldn't match type ‘a’ with ‘[a]’
Expected: [a] -> Bool
Actual: a -> Bool
‘a’ is a rigid type variable bound by
the type signature for:
takeAsLong :: forall a. [a] -> (a -> Bool) -> [a]
So why does it expect function test to be [a] -> Bool and why version with guards doesnt have same issue?
xs is a list of items except the first item. If you use [xs] then you wrapt that list in a singleton list.
You thus should call takeAsLong xs test instead of takeAsLong [xs] test:
takeAsLong :: [a] -> (a -> Bool) -> [a]
takeAsLong [] _ = []
takeAsLong (x:xs) test = if test x then x : takeAsLong xs test else []
Using an if-then-else is not that common. Usually the predicate will also be the first parameter. So a more "Haskell-ish" version is likely:
takeAsLong :: (a -> Bool) -> [a] -> [a]
takeAsLong p = go
where go [] = []
go (x:xs)
| p x = x : go xs
| otherwise = []
This function already exists and is known as takeWhile :: (a -> Bool) -> [a] -> [a]
The main problem here is in the part takeAsLong [xs] when you do that you are giving to the function takeAsLong :: [a] -> (a -> Bool) -> [a] a list of lists, takeAsLong :: [[a]] -> (a -> Bool) -> [a] that type is the one would work, but you type is the other one.
There is how to do it in #willem answer:
takeAsLong :: [a] -> (a -> Bool) -> [a]
takeAsLong [] _ = []
takeAsLong (x:xs) test = if test x then x : takeAsLong xs test else []

Why foldr (\ x xs -> x : x : xs) [] wont work?

I'm trying to see the difference in these 2 functions:
dupli = foldl (\acc x -> acc ++ [x,x]) []
dupli = foldr (\ x xs -> x : x : xs) []
I know the difference between foldl and foldr but for the examples I've seen on how it works, using (+), it looks the same except for the method of summing.
Why
dupli = foldr (\acc x -> acc ++ [x,x]) []
gives
/workspaces/hask_exercises/exercises/src/Lib.hs:142:27: error:
* Occurs check: cannot construct the infinite type: a ~ [a]
Expected type: [a]
Actual type: [[a]]
* In the expression: acc ++ [x, x]
In the first argument of `foldr', namely
`(\ acc x -> acc ++ [x, x])'
In the expression: foldr (\ acc x -> acc ++ [x, x]) []
* Relevant bindings include
x :: [a] (bound at src/Lib.hs:142:22)
acc :: [[a]] (bound at src/Lib.hs:142:18)
dupli' :: t [[a]] -> [a] (bound at src/Lib.hs:142:1)
|
142 | dupli' = foldr (\acc x -> acc ++ [x,x]) []
| ^^^^^^^^^^^^
exactly?
Look at the type signatures. (Note: I'm specializing both of these to [] rather than a general Foldable for simplicity here)
foldl :: (b -> a -> b) -> b -> [a] -> b
foldr :: (a -> b -> b) -> b -> [a] -> b
So in foldl, the "accumulator argument" is the first argument to the folding function, whereas in foldr, it's the second.
You mention (+). (+) is a function where the left-hand and right-hand arguments have the same type, so you wouldn't notice the difference. Specifically,
(+) :: Num a => a -> a -> a
But (:) is different.
(:) :: a -> [a] -> [a]
Since your initial accumulator is, in both cases, [], you can use (:) in the foldr case since the accumulator type [a] is the second argument, but in the foldl case we're required to do some tricks with ++.

Debugging type Errors in Haskell

I'm trying to write a function, returning all permutations from a list in Haskell:
perms :: [a] -> [[a]]
perms [] = [[]]
perms xs = map (\y -> concat_each y (perms (list_without y xs))) xs
list_without :: (Eq a) => a -> [a] -> [a]
list_without x xs =
filter (\y -> not (y==x)) xs
concat_each :: a -> [[a]] -> [[a]]
concat_each x xs =
map (\y -> x:y) xs
What I think happens in line3:
y is a and x is [a], so
list_without y xs is [a].
perms (list_without ...) is thus [[a]]
so concat_each y (perms ...) gets a and [[a]], resulting in [[a]]
So the function for map is a -> [[a]] and everything should be okay.
But the compiler seems to see things differently:
Couldn't match type `a' with `[a]'
`a' is a rigid type variable bound by
the type signature for perms :: [a] -> [[a]]
at C:\Users\Philipp\Desktop\permutations.hs:1:10
Expected type: [a]
Actual type: [[a]]
Relevant bindings include
y :: a (bound at permutations.hs:3:18)
xs :: [a] (bound at permutations.hs:3:7)
perms :: [a] -> [[a]]
(bound at permutations.hs:2:1)
In the expression: concat_each y (perms (list_without y xs))
In the first argument of `map', namely
`(\ y -> concat_each y (perms (list_without y xs)))'
How would I debug this error message properly? I don't really know where to start checking my types.
map :: (x -> y) -> [x] -> [y]
The first argument you gave to map has type a -> [[a]], i.e., x = a and y = [[a]] so
:: [x] -> [ y ]
map (\y -> ...) :: [a] -> [[[a]]]
-- ^ ^^^^^
-- x = a, y = [[a]]
In this case, the result of that map (\y -> ...) xs is a list where each element corresponds to the permutations starting with a fixed element y in xs. In the end, you don't care which element a permutation starts with; you can forget that separation using concat:
perms = concat (map (\y -> ...) xs)
-- or
perms = concatMap (\y -> ...) xs
-- or
perms = xs >>= \y -> ...

Haskell add to list in list

i have the following code
groupEq :: Eq a => [a] -> [[a]]
groupEq list = foldl (\acc x -> if (isType acc x) then ((last acc) ++ [x]) else acc++[[x]]) [] list
isType :: Eq a => [[a]] -> a -> Bool
isType list item
| (length list) == 0 = False
| head (last list) == item = True
| otherwise = False
Now, i am having difficulties understanding why it would not compile.
The problem is with the ((last acc) ++ [x]) part of it. I understand it as it takes the last element of accumulator, which would be [[a]] at this point and tries to add an element to it.
The idea what i want to achieve is this:
-- groupEq [1,2,2,3,3,3,4,1,1] ==> [[1], [2,2], [3,3,3], [4], [1,1]]
Full error is
Couldn't match type ‘a’ with ‘[a]’
‘a’ is a rigid type variable bound by
the type signature for groupEq :: Eq a => [a] -> [[a]]
at exam_revisited.hs:3:12
Expected type: [[[a]]]
Actual type: [[a]]
Relevant bindings include
x :: a (bound at exam_revisited.hs:4:28)
acc :: [[a]] (bound at exam_revisited.hs:4:24)
list :: [a] (bound at exam_revisited.hs:4:9)
groupEq :: [a] -> [[a]] (bound at exam_revisited.hs:4:1)
In the first argument of ‘last’, namely ‘acc’
In the first argument of ‘(++)’, namely ‘(last acc)’
What am i missing here?
groupEq is declared to return [[a]], but ((last acc) ++ [x]) is of type [a].
A quick and dirty solution is to change this expression into
init acc ++ [last acc ++ [x]].

Haskell - replicate elements in a list

I want to write a Haskell program that replicates the elements of a list a given number of times.
Here's my code:
repli :: [a] -> a -> [a]
repli xs n = foldl1 (\x -> take n (repeat x)) xs
My problem is I get the following errors when compiling:
'take' is applied to too many arguments
couldn't match expected type '[a]->[a]' with actual type '[[a]]'
The type signature for foldl1 is:
foldl1 :: (a -> a -> a) -> [a] -> a
Hence, the first argument needs to be a function of two arguments. The lambda expression you're passing only takes one argument. You probably meant to do something like this:
repli :: [a] -> Int -> [a]
repli xs n = concat $ map (\x -> take n (repeat x)) xs
Or, to do it better, you can use the replicate function:
repli :: [a] -> Int -> [a]
repli xs n = concat $ map (replicate n) xs
Or, to do it even betterer, you can use the [] monad:
repli :: [a] -> Int -> [a]
repli xs n = xs >>= replicate n
How about this very simple line:
repli :: [a] -> Int -> [a]
repli xs n = concat (replicate n xs)
Consider Prelude replicate before rolling out your own function: http://zvon.org/other/haskell/Outputprelude/replicate_f.html
repli xs n = foldr (++) [] (replicate n xs)
you can use "take" and "repeat". You also need to provide a base case where the list is empty.
repli [] _ = []
repli (x:xs) y = take y (repeat x) ++ repli xs y
A simple solution that worked for me
f :: Int -> [Int] -> [Int]
f n arr = concatMap (\num -> replicate n num) arr

Resources