I can't figure out how to implement the map and filter function for a matrix. Does anyone have any suggestions that would satisfy these tests?
-- | Matrix Tests
--
-- prop> mapMatrix (\a -> a - 3) (mapMatrix (+ 3) x) == x
--
-- >>> filterMatrix (< 3) matrix1
-- [[1,2],[2]]
-- >>> filterMatrix (> 80) []
-- []
-- >>> transpose' matrix2
-- [[1,4],[5,8]]
mapMatrix :: (a -> b) -> [[a]] -> [[b]]
mapMatrix f [list] = [map f list]
filterMatrix :: (a -> Bool) -> [[a]] -> [[a]]
filterMatrix = undefined
transpose' :: [[a]] -> [[a]]
transpose' = undefined
matrix1 = [[1 .. 10], [2 .. 20]]
matrix2 = [[1, 5], [4, 8]]
Some hints, but not a complete solution because this sounds like homework. mapmatrix and filterMatrix: write functions that work on one row of your matrix at a time, then map those onto the list of rows. transpose': one way to do this would be with a list comprehension that applies the !! operator to lists of indices, and another would be a recursive function that removes one row at a time from the input and adds one column at a time to the output.
Is filterMatrix supposed to return a list of lists that is not a valid matrix?
Related
When checking the type of map (!!) [1,2] in the ghci parser I get back: Num [a] => [Int -> a]. This has to do with the fact that the first argument of (!!) should be a list. However, I want to input a list of indices into the operator to get this type [a] -> [a].
EDIT
After the suggestion of #dfeuer to wrap it in another function I figured it would also be possible by using flip then. Checking the type of (map (flip (!!)) [1,2]) give the type [[c] -> c] which is what I am looking for.
If you have a list of indices and you want a function that selects those indices from an input list, then you want the map to iterate over the indices, not the input as you’re currently doing:
getIndices :: [Int] -> [a] -> [a]
getIndices indices input = map (input !!) indices
> getIndices [1, 2] "beans"
"ea"
If you want to write this in a more compact fashion using an inline list of indices, you can reduce away the input parameter like this:
\ input -> map (input !!) [1, 2]
\ input -> [1, 2] <&> (input !!) -- Data.Functor.(<&>) = flip (<$>)
\ input -> [1, 2] <&> (!!) input
\ input -> (([1, 2] <&>) . (!!)) input
([1, 2] <&>) . (!!)
In other words, flip map [1, 2] . (!!). But I think there isn’t anything to be gained from pointfree style in this case.
With a helper function (this name from lens):
flap, (??) :: Functor f => f (a -> b) -> a -> f b
flap f x = ($ x) <$> f
(??) = flap
infixl 1 ??
index :: Int -> [c] -> c
index = flip (!!)
This can be written:
> oneTwo = flap (index <$> [1, 2])
> oneTwo "beans"
"ea"
> index <$> [1, 2] ?? "bears"
"ea"
Or there’s always the boring but readable option of a list comprehension or do notation:
oneTwo xs = [xs !! i | i <- [1, 2]]
oneTwo xs = do { i <- [1, 2]; pure (xs !! i) }
I'm guessing you want
pickAndChoose :: [Int] -> [a] -> [a]
pickAndChoose indices values
= map (values !!) indices
Since !! takes time linear in the position of the element it retrieves, this will be quite inefficient if many indices are used, especially if they are relatively large. You may wish to consider using something like Data.Sequence instead of lists.
Basically I have this exercise:
Using list comprehensions, write a polymorphic function:
split :: [(a, b)] -> ([a], [b])
which transforms a list of pairs (of any types) into a pair of lists. For example,
split [(1, 'a'), (2, 'b'), (3, 'c')] = ([1, 2, 3], "abc")
This was the way I wrote the function but it is not working:
split :: [(a, b)] -> ([a], [b])
split listOfPairs = (([a | a <- listOfPairs]), ([b | b <- listOfPairs]))
Can someone please explain why my solution doesn't work? Thank you!
A list comprehension like:
[a | a <- listOfPairs]
is actually nothing more than an identity operation for lists. It will yield the same list as the one you provide, since you basically iterate over listOfPairs, and for each iteration, you yield the element a.
Haskell does not perform implicit conversions, so it does not derive from the types that a in your a <- listOfPairs then only can be the first element. Even if that was possible, it was probably not a good idea anyway, since it would make the language more "unstable" in the sense that a small change in the types, could have significant impact in the semantics.
In order to obtain the first element of a tuple, you need to use pattern matching, like:
[a | (a, _) <- listOfPairs]
here we thus pattern match the first element of the tuple with a, and for the second one, we thus use:
[b | (_, b) <- listOfPairs]
We can thus impelement this as:
split:: [(a,b)] -> ([a],[b])
split listOfPairs = ([a | (a, _) <- listOfPairs], [b | (_, b) <- listOfPairs])
Or we can use map :: (a -> b) -> [a] -> [b], fst :: (a, b) -> a and snd :: (a, b) -> b:
split:: [(a,b)] -> ([a],[b])
split listOfPairs = (map fst listOfPairs, map snd listOfPairs)
But the above still has a problem: here we iterate twice independently over the same list. We can omit that by using recursion, like:
split:: [(a,b)] -> ([a],[b])
split [] = []
split ((a, b):xs) = (a:as, b:bs)
where (as, bs) = split xs
or we can use a foldr function:
split :: Foldable f => f (a,b) -> ([a],[b])
split = foldr (\(a,b) (as,bs) -> (a:as,b:bs)) ([],[])
There is already a Haskell function that does exactly what you want: unzip :: [(a, b)] -> ([a], [b]), with the source code.
I'm not exactly sure if my nomenclature is correct here, but I was wondering if there was a zip function in Haskell that was greedy. This means that if I had
a = [1, 2, 3]
b = [4, 5]
zip' a b
#=> [(Just 1, Just 4),(Just 2, Just 5),(Just 3, Nothing)]
...where zip' is the greedy zip function, it would return a list of tuples the length of the longer list, and where the longer list has an element, but the shorter list does not Nothing is put in the respective tuple position. I am not asking how to write this, but instead was wondering if this exists as a built-in.
Here is my implementation (which is probably not great)
zip' :: [a] -> [b] -> [(Maybe a, Maybe b)]
zip' (a:xs) [] = (Just a, Nothing) : zip' xs []
zip' [] (b:ys) = (Nothing, Just b) : zip' [] ys
zip' [] _ = []
zip' (a:xs) (b:ys) = (Just a, Just b) : zip' xs ys
A greedy zip can be neatly expressed through a non-exclusive disjunction type (as opposed to Either, which is an exclusive disjunction). Two popular packages offer that. One is the minimalist, dependency-free data-or:
GHCi> import Data.Or
GHCi> :t zipOr
zipOr :: [a] -> [b] -> [Or a b]
GHCi> zipOr [1, 2, 3] [4, 5]
[Both 1 4,Both 2 5,Fst 3]
The other is these, which comes with lots of bells and whistles:
GHCi> import Data.These
GHCi> import Data.Align
GHCi> :t align
align :: Align f => f a -> f b -> f (These a b)
GHCi> align [1, 2, 3] [4, 5]
[These 1 4,These 2 5,This 3]
I believe Or a b and These a b express your intent better than (Maybe a, Maybe b) (the latter type includes (Nothing, Nothing), which a greedy zip will never produce). Still, you can express your zip' using either zipOrWith from Data.Or...
import Data.Or
zip' :: [a] -> [b] -> [(Maybe a, Maybe b)]
zip' = zipOrWith $ \xy -> case xy of
Both x y -> (Just x, Just y)
Fst x -> (Just x, Nothing)
Snd y -> (Nothing, Just y)
... or alignWith from Data.Align:
import Data.These
import Data.Align
zip' :: Align f => f a -> f b -> f (Maybe a, Maybe b)
zip' = alignWith $ \xy -> case xy of
These x y -> (Just x, Just y)
This x -> (Just x, Nothing)
That y -> (Nothing, Just y)
Data.Align, in fact, provides your function under the name of padZip.
I want to do a list of concatenations in Haskell.
I have [1,2,3] and [4,5,6]
and i want to produce [14,15,16,24,25,26,34,35,36].
I know I can use zipWith or sth, but how to do equivalent of:
foreach in first_array
foreach in second_array
I guess I have to use map and half curried functions, but can't really make it alone :S
You could use list comprehension to do it:
[x * 10 + y | x <- [1..3], y <- [4..6]]
In fact this is a direct translation of a nested loop, since the first one is the outer / slower index, and the second one is the faster / inner index.
You can exploit the fact that lists are monads and use the do notation:
do
a <- [1, 2, 3]
b <- [4, 5, 6]
return $ a * 10 + b
You can also exploit the fact that lists are applicative functors (assuming you have Control.Applicative imported):
(+) <$> (*10) <$> [1,2,3] <*> [4,5,6]
Both result in the following:
[14,15,16,24,25,26,34,35,36]
If you really like seeing for in your code you can also do something like this:
for :: [a] -> (a -> b) -> [b]
for = flip map
nested :: [Integer]
nested = concat nested_list
where nested_list =
for [1, 2, 3] (\i ->
for [4, 5, 6] (\j ->
i * 10 + j
)
)
You could also look into for and Identity for a more idiomatic approach.
Nested loops correspond to nested uses of map or similar functions. First approximation:
notThereYet :: [[Integer]]
notThereYet = map (\x -> map (\y -> x*10 + y) [4, 5, 6]) [1, 2, 3]
That gives you nested lists, which you can eliminate in two ways. One is to use the concat :: [[a]] -> [a] function:
solution1 :: [Integer]
solution1 = concat (map (\x -> map (\y -> x*10 + y) [4, 5, 6]) [1, 2, 3])
Another is to use this built-in function:
concatMap :: (a -> [b]) -> [a] -> [b]
concatMap f xs = concat (map f xs)
Using that:
solution2 :: [Integer]
solution2 = concatMap (\x -> map (\y -> x*10 + y) [4, 5, 6]) [1, 2, 3]
Other people have mentioned list comprehensions and the list monad, but those really bottom down to nested uses of concatMap.
Because do notation and the list comprehension have been said already. The only other option I know is via the liftM2 combinator from Control.Monad. Which is the exact same thing as the previous two.
liftM2 (\a b -> a * 10 + b) [1..3] [4..6]
The general solution of the concatenation of two lists of integers is this:
concatInt [] xs = xs
concatInt xs [] = xs
concatInt xs ys = [join x y | x <- xs , y <- ys ]
where
join x y = firstPart + secondPart
where
firstPart = x * 10 ^ lengthSecondPart
lengthSecondPart = 1 + (truncate $ logBase 10 (fromIntegral y))
secondPart = y
Example: concatInt [1,2,3] [4,5,6] == [14,15,16,24,25,26,34,35,36]
More complex example:
concatInt [0,2,10,1,100,200] [24,2,999,44,3] == [24,2,999,44,3,224,22,2999,244,23,1024,102,10999,1044,103,124,12,1999,144,13,10024,1002,100999,10044,1003,20024,2002,200999,20044,2003]
this is what I have for matrix addition in Haskell
> add :: (Num a) => [[a]] -> [[a]] -> [[a]]
> add [] [] = []
> add (x:xs) (y:ys) = zipWith (+) x y : add xs ys
add [[1,2], [3,4]] [[5,6], [7,8]] gives me [[6,8],[10,12]]
However, I am trying do with one line instead
> add :: (Num a) => [[a]] -> [[a]] -> [[a]]
> add = map ((zipWith (+))
How come the map function doesn't work?
The map function doesn't work here because you're iterating over two lists instead of one. To iterate over two lists in parallel, you use zipWith, just like you are already doing for the inner loop.
Prelude> let add = zipWith (zipWith (+))
Prelude> add [[1, 2], [3, 4]] [[5, 6], [7, 8]]
[[6,8],[10,12]]
map takes in a single list: you're trying to give it two.
Try something like:
add = zipWith (zipWith (+))