I have a list of tuples which looks like this in Haskell:
([],[[]],[])
And I want to perform some operations on these lists and return all possible changes of state onto them. I want to return a list of this tuple and I am not quite sure how to bind them together. When I tried cons or ++ I get some errors.
([],[[]],[]):([],[[]],[])
([],[[]],[])++([],[[]],[])
<interactive>:81:1:
Couldn't match expected type ‘[a]’
with actual type ‘([t0], [t1], [t2])’
Relevant bindings include it :: [a] (bound at <interactive>:81:1)
In the first argument of ‘(++)’, namely ‘([], [], [])’
In the expression: ([], [], []) ++ ([], [], [])
In an equation for ‘it’: it = ([], [], []) ++ ([], [], [])
your main problem here is that you have an tuple of lists instead of a list of tuples as you claimed - so of course neither : nor ++ will work.
Maybe you want to use those operations component-wise, which can be done by something like:
map3 :: (a -> b -> c) -> (a, a, a) -> (b, b, b) -> (c, c, c)
map3 op (xs,ys,zs) (xs',ys',zs') = (xs `op` xs',ys `op` ys',zs `op` zs')
using this you get:
λ> map3 (++) ([],[[]],[]) ([],[[]],[])
([],[[],[]],[])
λ> map3 (:) ([],[[]],[]) ([],[[]],[])
([[]],[[[]],[]],[[]])
if this is not what you expected / wanted then please add an example on what you want
Related
I want to write a recursive function that gets two lists + a conditional as input, and outputs all possible tuples with one element each from the 1st and 2nd lists that satisfy the condition.
It should look something like this:
Combine [1,2,3] [5,6,7] (\a b -> a+b > 7) -> [(1,7),(2,6),(2,7),(3,5),(3,6),(3,7)]
I got this atm:
Combine:: [a] -> [b] -> [(a, b)]
Combine [] ys = []
Combine xs [] = []
Combine (x:xs) (y:ys) = (x,y) : Combine xs ys
However, it does not yet create all possible combinations and does not filter by condition. I really don't know how to figure this out.
Thanks in advance
You don't need a recursive function, but you need a higher order function.
combinationsFilter :: (a -> b -> Bool) -> [a] -> [b] -> [(a,b)]
combinationsFilter f as bs = filter (uncurry f) [(a, b) | a <- as, b <- bs]
[(a, b) | a <- as, b <- bs] generates all combinations of a and b.
filter... just filters the list by condition.
uncurry needed if you want pass a function with type (a -> b -> c), but not ((a, b) -> c). It converts one to the other.
Apologies for the awful title, I'm not too sure how to describe it in words but here is what I mean. If you know a better way to phrase this please let me know.
Suppose I had 2 lists, of equal length.
[a, b, c] [x, y, z]
I want to create the list
[[a, y, z], [b, x, z], [c, x, y]]
Essentially for every element of list1, I want the 2 elements at different indexes to the first element in list2.
so for "a" at index 0, the other 2 are "y" at index 1 and "z" at index 2.
I'm pretty sure I know how to do it using indexes, however, I know that that's not very efficient and wanted to see if there is a more functional solution out there.
Thank you.
You haven't described any edge cases, but you can get the basic behavior you're looking for with something like:
import Data.List (inits, tails)
combine :: [a] -> [a] -> [[a]]
combine xs ys = zipWith3 go xs (tails ys) (inits ys)
where
go a (_:xs) ys = a:ys ++ xs
go _ _ _ = []
The key is that tails returns successive suffixes of its list starting with the full list, and inits returns successive prefixes starting with the empty list.
I would do it using zippers. Here's a function I've written into so many projects I've memorized it:
zippers :: [a] -> [([a], a, [a])]
zippers = go [] where
go b [] = []
go b (h:e) = (b, h, e) : go (h:b) e
(This actually returns a bit more information than we technically need for this application. But it is the general form -- useful in many situations where the restricted version that only returned the prefix/suffix pair and omitted the current focus would sometimes not be enough.)
With this tool in hand, we can just zip (different kind of zip!) together the values from the one list with the zippers of the other list.
combine :: [a] -> [a] -> [[a]]
combine xs ys = zipWith (\x (b, h, e) -> reverse b ++ [x] ++ e) xs (zippers ys)
Try it out in ghci:
> combine "abc" "xyz"
["ayz","xbz","xyc"]
You can try this:
\xs ys -> zipWith3 (((++) .) . (:)) xs (init $ inits ys) (tail $ tails ys)
I want to concat in a list of tuples of elements and Strings, each char with the element.
For example: [(True, "xy"), (False, "abc")] -> [(True,’x’),(True,’y’),(False,’a’), (False,’b’),(False,’c’)]
I do have a solution, but im wondering if there is a better one:
concatsplit :: [(a,[b])] -> [(a,b)]
concatsplit a = concatMap (\(x,y)-> concatsplit' (x,y)) a
concatsplit' :: (a,[b]) -> [(a,b)]
concatsplit' y = map (\x -> ((fst y),x)) (snd y)
Why not a simple list comprehension?
List comprehensions can often do as much as higher order functions, and I think that if you don't need to change the data but only "unpack" it, they are pretty clear. Here's a working example:
concS :: [(a,[b])] -> [(a,b)]
concS ls = [(a,b) | (a,x) <- ls, b <- x]
The other answers show how to do this idiomatically from scratch, which I like a lot. It might also be interesting to show how you might polish what you've already got. Here it is again as a reminder:
concatsplit a = concatMap (\(x,y)-> concatsplit' (x,y)) a
concatsplit' y = map (\x -> ((fst y),x)) (snd y)
The first thing I'd consistently change is called "eta reduction", and it is when you turn something of the shape \x -> foo x into just foo. We can do this in the argument to concatMap to get
concatsplit a = concatMap concatsplit' a
and then again in the argument to concatsplit to get:
concatsplit = concatMap concatsplit'
Looking at concatsplit', the thing I like least is the use of fst and snd instead of pattern matching. With pattern matching, it looks like this:
concatsplit' (a,bs) = map (\x -> (a,x)) bs
If you really wanted to practice your eta reduction, you might notice that (,) can be applied prefix and change this to
concatsplit' (a,bs) = map (\x -> (,) a x) bs
= map ((,) a) bs
but I think I'm just as happy one way or the other. At this point, this definition is small enough that I'd be tempted to inline it into concatsplit itself, getting:
concatsplit = concatMap (\(a,bs) -> map ((,) a) bs)
This looks like a pretty good definition to me, and I'd stop there.
You might be bugged by the almost-eta-reduction here: it's almost the right shape to drop the bs. An advanced user might go on, noticing that:
uncurry (\a bs -> map ((,) a) bs) = \(a,bs) -> map ((,) a) bs
Hence with some eta reduction and other point-free techniques, we could transition this way:
concatsplit = concatMap (uncurry (\a bs -> map ((,) a) bs))
= concatMap (uncurry (\a -> map ((,) a)))
= concatMap (uncurry (map . (,)))
But, personally, I find this less readable than where I declared I would stop above, namely:
concatsplit = concatMap (\(a,bs) -> map ((,) a) bs)
sequenceA makes it really easy:
concatsplit = concatMap sequenceA
Or generalize it even further:
concatsplit = (>>= sequenceA)
Details:
sequenceA has type (Applicative f, Traversable t) => t (f a) -> f (t a). This means that if you have a type with a Traversable on the "outside" and an Applicative on the "inside", you can call sequenceA on it to turn it inside-out, so that the Applicative is on the "outside" and the Traversable is on the "inside".
In this case, (True, "xy") has type (Bool, [Char]), which desugars to (,) Bool ([] Char). There's an instance of Traversable for ((,) a), and there's an instance of Applicative for []. Thus, you can call sequenceA on it, and the result will be of type [] ((,) Bool Char), or [(Bool, Char)] with sugar.
As it turns out, not only does sequenceA have a useful type, but it does exactly the thing you need here (and turns out to be exactly equivalent to concatsplit').
concatMap has type Foldable t => (a -> [b]) -> t a -> [b]. (>>=) has type Monad m => m a -> (a -> m b) -> m b. When specialized to lists, these become the same, except with their arguments in the opposite order.
You can also use the monad instance for lists:
concatSplit l = l >>= \(a,x) -> x >>= \b -> return (a,b)
Which can be simplified to:
concatSplit l = l >>= \(a,x) -> map ((,) a) x
And reformatted to do notation
concatSplit l = do
(a,x) <- l
map ((,) a) x
I am dealing with small program with Haskell. Probably the answer is really simple but I try and get no result.
So one of the part in my program is the list:
first = [(3,3),(4,6),(7,7),(5,43),(9,9),(32,1),(43,43) ..]
and according to that list I want to make new one with element that are equal in the () =:
result = [3,7,9,43, ..]
Even though you appear to have not made the most minimal amount of effort to solve this question by yourself, I will give you the answer because it is so trivial and because Haskell is a great language.
Create a function with this signature:
findIdentical :: [(Int, Int)] -> [Int]
It takes a list of tuples and returns a list of ints.
Implement it like this:
findIdentical [] = []
findIdentical ((a,b) : xs)
| a == b = a : (findIdentical xs)
| otherwise = findIdentical xs
As you can see, findIdentical is a recursive function that compares a tuple for equality between both items, and then adds it to the result list if there is found equality.
You can do this for instance with list comprehension. We iterate over every tuple f,s) in first, so we write (f,s) <- first in the right side of the list comprehension, and need to filter on the fact that f and s are equal, so f == s. In that case we add f (or s) to the result. So:
result = [ f | (f,s) <- first, f == s ]
We can turn this into a function that takes as input a list of 2-tuples [(a,a)], and compares these two elements, and returns a list [a]:
f :: Eq a => [(a,a)] -> [a]
f dat = [f | (f,s) <- dat, f == s ]
An easy way to do this is to use the Prelude's filter function, which has the type definition:
filter :: (a -> Bool) -> [a] -> [a]
All you need to do is supply predicate on how to filter the elements in the list, and the list to filter. You can accomplish this easily below:
filterList :: (Eq a) => [(a, a)] -> [a]
filterList xs = [x | (x, y) <- filter (\(a, b) -> a == b) xs]
Which behaves as expected:
*Main> filterList [(3,3),(4,6),(7,7),(5,43),(9,9),(32,1),(43,43)]
[3,7,9,43]
I have to write a function that flattens a list of lists.
For example flatten [] = [] or flatten [1,2,3,4] = [1,2,3,4] or flatten [[1,2],[3],4,5]] = [1,2,3,4,5]
I'm having trouble with the being able to match the type depending on what is given to the flatten function.
Here's what I have:
data A a = B a | C [a] deriving (Show, Eq, Ord)
flatten::(Show a, Eq a, Ord a)=>A a -> A a
flatten (C []) = (C [])
flatten (C (x:xs) ) = (C flatten x) ++ (C flatten xs)
flatten (B a) = (C [a])
From what I can tell the issue is that the ++ operator is expecting a list for both of its arguments and I'm trying to give it something of type A. I've added the A type so the function can either get a single element or a list of elements.
Does anyone know a different way to do this differently, or explain what I can do to fix the type error?
It's a bit unclear what you are asking for, but flattening a list of list is a standard function called concat in the prelude with type signature [[a]] -> [a].
If you make a data type of nested lists as you have started above, maybe you want to adjust your data type to something like this:
data Lists a = List [a] | ListOfLists [Lists a]
Then you can flatten these to a list;
flatten :: Lists a -> [a]
flatten (List xs) = xs
flatten (ListOfLists xss) = concatMap flatten xss
As a test,
> flatten (ListOfLists [List [1,2],List [3],ListOfLists [List [4],List[5]]])
[1,2,3,4,5]
Firstly, the A type is on the right track but I don't think it's quite correct. You want it to be able to flatten arbitrarily nested lists, so a value of type "A a" should be able to contain values of type "A a":
data A a = B a | C [A a]
Secondly, the type of the function should be slightly different. Instead of returning a value of type "A a", you probably want it to return just a list of a, since by definition the function is always returning a flat list. So the type signature is thus:
flatten :: A a -> [a]
Also note that no typeclass constraints are necessary -- this function is completely generic since it does not look at the list's elements at all.
Here's my implementation:
flatten (B a) = [a]
flatten (C []) = []
flatten (C (x:xs)) = flatten x ++ flatten (C xs)
this one liner will do the job. Although as it was mentioned by Malin the type signature is different:
flatten :: [[a]] -> [a]
flatten xs = (\z n -> foldr (\x y -> foldr z y x) n xs) (:) []
simple test
frege> li = [[3,4,2],[1,9,9],[5,8]]
frege> flatten li
[3,4,2,1,9,9,5,8]
Flatten via list comprehension.
flatten arr = [y | x<- arr, y <- x]