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 -> ...
Related
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 ++.
I'm not sure what this error message wants me to change as I can't see the issue with my code but clearly there's something wrong otherwise it would compile.
Error message:
* Couldn't match expected type `(a, a)' with actual type `[(a, a)]'
* In the expression: xs ++ (flips xs)
In the expression: [xs ++ (flips xs)]
In an equation for `symClosure': symClosure xs = [xs ++ (flips xs)]
* Relevant bindings include
xs :: [(a, a)]
symClosure :: [(a, a)] -> [(a, a)]
symClosure xs = [xs ++ (flips xs)]
Code:
heads :: (Eq a) => [(a,a)] -> [a]
heads xs = [x | (x, _) <- xs]
tails :: (Eq a) => [(a,a)] -> [a]
tails xs = [x | (_,x) <- xs]
flips :: [a] -> [(a,a)]
flips xs = tails xs ++ heads xs
symClosure :: (Eq a) => [(a,a)] -> [(a,a)]
symClosure xs = [xs ++ (flips xs)]
Side note: I can't import anything and I can't change signatures.
Again, any info to help me understand is very much appreciated :)
I think your flips does not do what its signature says it does:
heads :: (Eq a) => [(a,a)] -> [a]
tails :: (Eq a) => [(a,a)] -> [a]
(++) :: [a] -> [a] -> [a]
in other words, with your definition this signature is correct:
flips :: [(a, a)] -> [a]
flips xs = tails xs ++ heads xs
Note that you can only call tails and heads on lists of pairs. Also note you can leave out the Eq constraint from all the signatures above.
If you meant to reverse the tuples, you can use zip instead
flips :: [(a, a)] -> [(a, a)]
flips xs = tails xs `zip` heads xs
As for symClosure, taking the definition of flips above, the expression
symClosure xs = [xs ++ (flips xs)]
would produce a list with a single element, itself a list of pairs. That explains why it is saying that the (a, a) in your signature does not match the [(a, a)] it infers from the expression. You probably need to leave the brackets out.
symClosure xs = xs ++ flips xs
I want to filter a list by predicates curried from another list.
For instance:
multifilter :: (a -> a -> Bool) -> [a] -> [a] -> [a]
multifilter _ _ [] = []
multifilter _ [] _ = []
multifilter f (x:xs) ys = (filter (f x) ys) ++ (multifilter f xs ys)
With usage such as:
prelude> multifilter (==) [1,2,3] [5,3,2]
[2,3]
Is there a standard way to do this?
You can use intersectBy:
λ> :t intersectBy
intersectBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]
λ> intersectBy (==) [1,2,3] [5,3,2]
[2,3]
You can use hoogle to search functions using type signature and finding them.
Note: This answer implements the specification expressed by the words and example in the question, rather than the different one given by the implementation of multifilter there. For the latter possibility, see gallais' answer.
Sibi's answer shows how you should actually do it. In any case, it is instructive to consider how you might write your function using filter. To begin with, we can establish two facts about it:
multifilter can be expressed directly as filter pred for some appropriate choice of pred. Given a fixed "predicate list", whether an element of the list you are multifiltering will be in the result only depends on the value of that element.
In multifilter f xs ys, the list you are filtering is xs, and the "predicate list" is ys. Were it not so, you would get [3,2] rather than [2,3] in your (quite well-chosen) example.
So we have:
multifilter :: (a -> a -> Bool) -> [a] -> [a] -> [a]
multifilter f xs ys = filter pred xs
where
pred = undefined -- TODO
All we need to do is implementing pred. Given an element x, pred should produce True if, for some element y of ys, f x y is true. We can conveniently express that using any:
pred x = any (\y -> f x y) ys
-- Or, with less line noise:
pred x = any (f x) ys
Therefore, multifilter becomes...
multifilter :: (a -> a -> Bool) -> [a] -> [a] -> [a]
multifilter f xs ys = filter pred xs
where
pred x = any (f x) ys
-- Or, more compactly:
multifilter :: (a -> a -> Bool) -> [a] -> [a] -> [a]
multifilter f xs ys = filter (\x -> any (f x) ys) xs
... which is essentially equivalent to intersectBy, as you can see by looking at intersectBy's implementation.
A third option is to use a list comprehension:
multifilter rel xs ys = [ x | x <- xs, y <- ys, x `rel` y ]
or, if you want partial application:
multifilter p xs ys = [ x | x <- xs, let f = p x, y <- ys, f y ]
If you want to use filter,
relate rel xs ys = filter (uncurry rel) $ liftM2 (,) xs ys
(and throw in map fst)
The answer you have accepted provides a function distinct from the one defined in your post: it retains elements from xs when yours retains elements from ys. You can spot this mistake by using a more general type for multifilter:
multifilter :: (a -> b -> Bool) -> [a] -> [b] -> [b]
Now, this can be implemented following the specification described in your post like so:
multifilter p xs ys = fmap snd
$ filter (uncurry p)
$ concatMap (\ x -> fmap (x,) ys) xs
If you don't mind retaining the values in the order they are in in ys then you can have an even simpler definition:
multifilter' :: (a -> b -> Bool) -> [a] -> [b] -> [b]
multifilter' p xs = filter (flip any xs . flip p)
Simply use Hoogle to find it out via the signature (a -> a -> Bool) -> [a] -> [a] -> [a]
https://www.haskell.org/hoogle/?hoogle=%28a+-%3E+a+-%3E+Bool%29+-%3E+%5Ba%5D+-%3E+%5Ba%5D+-%3E+%5Ba%5D
yields intersectBy:
intersectBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]
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].
I did it like this – but it is not working:
ma f [] = []
ma f (xs) = foldl (\y ys -> ys++(f y)) [] xs
foldl :: (a -> b -> a) -> a -> [b] -> a
foldr :: (a -> b -> b) -> b -> [a] -> b
Why is there a difference in the function that fold takes. I mean, (a -> b -> a) and (a -> b -> b)?
Is it possible to define map using foldl?
I have another question
I have an expr.
map (:)
I want to know what it will do. I tried to test it but i only get error.
type is map (:) :: [a] -> [[a] -> [a]]
I tried to send in a list of [1,2,3]
Not if you want it to work for infinite as well as finite lists. head $ map id (cycle [1]) must return 1.
foldling over an infinite list diverges (never stops), because foldl is recursive. For example,
foldl g z [a,b,c] = g (g (g z a) b) c
Before g gets a chance to ignore its argument, foldl must reach the last element of the input list, to construct the first call to g. There is no last element in an infinite list.
As for your new question, here's a GHCi transcript that shows that map (:) is a function, and map (:) [1,2,3] is a list of functions, and GHCi just doesn't know how to Show functions:
Prelude> map (:)
<interactive>:1:0:
No instance for (Show ([a] -> [[a] -> [a]]))
Prelude> :t map (:)
map (:) :: [a] -> [[a] -> [a]]
Prelude> map (:) [1,2,3]
<interactive>:1:0:
No instance for (Show ([a] -> [a]))
Prelude> :t map (:) [1,2,3]
map (:) [1,2,3] :: (Num a) => [[a] -> [a]]
Prelude> map ($ [4]) $ map (:) [1,2,3]
[[1,4],[2,4],[3,4]]
Prelude> foldr ($) [4] $ map (:) [1,2,3]
[1,2,3,4]
It becomes more obvious when you swap the type-variable names in one of the functions:
foldl :: (b -> a -> b) -> b -> [a] -> b
foldr :: (a -> b -> b) -> b -> [a] -> b
...because after all, what we need is the result, i.e. [a] -> b. Or, more specially, [a] -> [b], so we might as well substitute that
foldl :: ([b] -> a -> [b]) -> [b] -> [a] -> [b]
foldr :: (a -> [b] -> [b]) -> [b] -> [a] -> [b]
which leaves only one non-list item in each signature, namely the a. That's what we can apply f to, so, in the case of foldl it has to be the 2nd argument of the lambda:
foldl (\ys y -> ys ++ f y)
As Xeo remarks, this isn't done yet, because f y has type b, not [b]. I think you can figure out how to fix that yourself...
ma f [] = []
ma f (xs) = foldl (\ys y -> ys++[(f y)]) [] xs
Works but why does order of arg to lambda matter.
ma f (xs) = foldl (\y ys -> ys++[(f y)]) [] xs gives error