Haskell map list of indices to !! operator - haskell

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.

Related

Stack overflow when folding infinite lists?

Consider the following function:
(<.>) :: [[a]] -> [[a]] -> [[a]]
xs <.> ys = zipWith (++) xs ys
This essentially takes two two-dimensional arrays of as and concatanates them, left to right, e.x.:
[[1,2],[3,4]] <.> [[1,2],[3,4]] == [[1,2,1,2],[3,4,3,4]]
I would like to be able to write something like the following:
x = foldr1 (<.>) $ repeat [[1,2],[3,4]]
Which should make sense due to Haskell's lazy evaluation, i.e. we should obtain:
x !! 0 == [1,2,1,2,1,2,1,2...]
x !! 1 == [3,4,3,4,3,4,3,4...]
However, when I try to run this example with GHCi, either using foldr1 or foldl1, I either get a non-terminating computation, or a stack overflow.
So my question is:
What's going on here?
Is it possible to do what I'm trying to accomplish here with some function other than foldr1 or foldl1? (I'm happy if I need to modify the implementation of <.>, as long as it computes the same function)
Also, note: I'm aware that for this example, map repeat [[1,2],[3,4]] produces the desired output, but I am looking for a solution that works for arbitrary infinite lists, not just those of the form repeat xs.
I'll expand on what's been said in the comments here. I'm going to borrow (a simplified version of) the GHC version of zipWith, which should suffice for the sake of this discussion.
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith f [] _ = []
zipWith f _ [] = []
zipWith f (x:xs) (y:ys) = f x y : zipWith f xs ys
Now, here's what your computation ends up looking like, in it's glorious infinite form.
[[1, 2], [3, 4]] <.> ([[1, 2], [3, 4]] <.> ([[1, 2], [3, 4]] ... ) ... )
Okay, so the top-level is a <.>. Fine. Let's take a closer look at that.
zipWith (++) [[1, 2], [3, 4]] ([[1, 2], [3, 4]] <.> ([[1, 2], [3, 4]] ... ) ... )
Still no problems yet. Now we look at the patterns for zipWith. The first pattern only matches if the left-hand-side is empty. Welp, that's definitely not true, so let's move on. The second only matches if the right-hand-side is empty. So let's see if the right-hand-side is empty. The right-hand-side looks like
[[1, 2], [3, 4]] <.> ([[1, 2], [3, 4]] <.> ([[1, 2], [3, 4]] ... ) ... )
Which is what we started with. So to compute the result, we need access to the result. Hence, stack overflow.
Now, we've established that our problem is with zipWith. So let's play with it. First, we know we're going to be applying this to infinite lists for our contrived example, so we don't need that pesky empty list case. Get rid of it.
-- (I'm also changing the name so we don't conflict with the Prelude version)
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys
(<.>) :: [[a]] -> [[a]] -> [[a]]
xs <.> ys = zipWith' (++) xs ys
But that fixes nothing. We still have to evaluate to weak head normal form (read: figure out of the list is empty) to match that pattern.
If only there was a way to do a pattern match without having to get to WHNF... enter lazy patterns. Let's rewrite our function this way.
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f ~(x:xs) ~(y:ys) = f x y : zipWith' f xs ys
Now our function will definitely break if given a finite list. But this allows us to "pretend" pattern match on the lists without actually doing any work. It's equivalent to the more verbose
zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f xs ys = f (head xs) (head ys) : zipWith' f (tail xs) (tail ys)
And now we can test your function properly.
*Main> let x = foldr1 (<.>) $ repeat [[1, 2], [3, 4]]
*Main> x !! 0
[1,2,1,2,1,2,1,2,1,...]
*Main> x !! 1
[3,4,3,4,3,4,3,4,3,...]
The obvious downside of this is that it will definitely fail on finite lists, so you have to have a different function for those.
*Main> [[1, 2], [3, 4]] <.> [[1, 2], [3, 4]]
[[1,2,1,2],[3,4,3,4],*** Exception: Prelude.head: empty list
zipWith is not -- in fact, it can't possibly be -- as lazy as you'd like. Consider this variation on your example:
GHCi> foldr1 (zipWith (++)) [ [[1,2],[3,4]], [] ]
[]
Any empty list of lists in the input will lead to an empty list of lists result. That being so, there is no way to know any of the elements of the result until the whole input has been consumed. Therefore, your function won't terminate on infinite lists.
Silvio Mayolo's answer goes through some potential workarounds for this issue. My suggestion is using non-empty-lists of lists, instead of plain lists of lists:
GHCi> import qualified Data.List.NonEmpty as N
GHCi> import Data.List.NonEmpty (NonEmpty(..))
GHCi> take 10 . N.head $ foldr1 (N.zipWith (++)) $ repeat ([1,2] :| [[3,4]])
[1,2,1,2,1,2,1,2,1,2]
N.zipWith doesn't have to deal with an empty list case, so it can be lazier.

Using map and filter function

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?

Nested loop equivalent

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]

Haskell: Using map in function composition

I am relatively new to Haskell so apologies if my question sounds stupid. I have been trying to understand how function composition works and I have come across a problem that I was wondering someone could help me with. I am using map in a function composition in the following two scenarios:
map (*2) . filter even [1,2,3,4]
map (*2) . zipWith max [1,2] [4,5]
Although both the filter and zipWith functions return a list, only the first composition works while the second composition throws the below error:
"Couldn't match expected type '[Int] -> [Int]' with actual type '[c0]'
Any suggestions would be greatly appreciated.
Recall the type of (.).
(.) :: (b -> c) -> (a -> b) -> a -> c
It takes three arguments: two functions and an initial value, and returns the result of the two functions composed.
Now, application of a function to its arguments binds tighter than the (.) operator.
So your expression:
map (*2) . filter even [1,2,3,4]
is parsed as:
(.) (map (*2)) (filter even [1,2,3,4])
now, the first argument, map (*2) is ok. It has type (b -> c), where b and c is Num a => [a]. However, the second argument is a single list:
Prelude> :t filter even [1,2,3,4]
filter even [1,2,3,4] :: Integral a => [a]
and so the type checker will complain that you're passing a [a] as an argument when the (.) function needs a function.
And that's what we see:
Couldn't match expected type `a0 -> [b0]' with actual type `[a1]'
In the return type of a call of `filter'
In the second argument of `(.)', namely `filter even [1, 2, 3, 4]'
In the expression: map (* 2) . filter even [1, 2, 3, 4]
So... parenthesization!
Either use the $ operator to add a parenthesis:
map (*2) . filter even $ [1,2,3,4]
or use explicit parens, removing the composition of two functions
map (*2) (filter even [1,2,3,4])
or even:
(map (*2) . filter even) [1,2,3,4]
The following forms are valid:
map (* 2) $ filter even [1, 2, 3, 4]
(map (* 2) . filter even) [1, 2, 3, 4]
map (* 2) $ zipWith max [1, 2] [4, 5]
(\xs -> map (* 2) . zipWith max xs) [1, 2] [4, 5]
but not the following:
map (* 2) . filter even [1, 2, 3, 4]
map (* 2) . zipWith max [1, 2] [4, 5]
(map (* 2) . zipWith max) [1, 2] [4, 5]
Why is that so? Well, take for example
map (* 2) . zipWith max [1, 2] [4, 5]
it is the same as
(map (* 2)) . (((zipWith max) [1, 2]) [4, 5])
(map (* 2)) has type [Int] -> [Int] (assuming defaulting for Int), (((zipWith max) [1, 2]) [4, 5]) has type [Int] and (.) has type (b -> c) -> (a -> b) -> a -> c or ([Int] -> [Int]) -> ([Int] -> [Int]) -> [Int] -> [Int] in this non-polymorphic case, so this is ill-typed. On the other hand ($) has type (a -> b) -> a -> b, or ([Int] -> [Int]) -> [Int] -> [Int] in this non-polymorphic case, so this:
(map (* 2)) $ (((zipWith max) [1, 2]) [4, 5])
is well-typed.
The result of zipWith max [1,2] [4,5] is a list, not a function. The (.) operator requires a function as its right operand. Hence the error on your second line. Probably what you want is
map (*2) (zipWith max [1,2] [4,5])
Your first example does not compile on WinHugs (Hugs mode); it has the same error. The following will work
(map (*2) . filter even) [1,2,3,4]
as it composes two functions and applies the resulting function to an argument.
Due to the low precedence of (.), Haskell parses
map (*2) . filter even [1,2,3,4]
as
map (*2) . (filter even [1,2,3,4])
i.e. compose map (*2) (a function) with the result of filter even [1,2,3,4] (a list), which makes no sense, and is a type error.
You can fix this using #Theodore's suggestions, or by using ($):
map (*2) . filter even $ [1,2,3,4]
If you check the type of map it is: (a -> b) -> [a] -> [b]
So, it takes a function of a into b and then a list of a and returns a list of b. Right?
Now, you already provide a function of a into b by passing the parameter (*2). So, your partially applied map function end up being: [Integer] -> [Integer] meaning that you will receive a list of integers and return a list of integers.
Up to this point, you could compose (.) a function that has the same signature. If you check what is the type of filter even you would see that it is: [Integer] -> [Integer], as such a valid candidate for composition here.
This composition then, does not alter the final signature of the function, if you check the type of: map (*2) . filter even it is [Integer] -> [Integer]
This would not be the case of the map (*2) . zipWith max [1,2] [4,5] because the zipWith max does not have the same signature as the one expected by map (*2).

Best practice how to evaluate a list of Maybes

i am looking for a function which takes a function (a -> a -> a) and a list of [Maybe a] and returns Maybe a. Hoogle gave me nothing useful. This looks like a pretty common pattern, so i am asking if there is a best practice for this case?
>>> f (+) [Just 3, Just 3]
Just 6
>>> f (+) [Just 3, Just 3, Nothing]
Nothing
Thanks in advance, Chris
You should first turn the [Maybe a] into a Maybe [a] with all the Just elements (yielding Nothing if any of them are Nothing).
This can be done using sequence, using Maybe's Monad instance:
GHCi> sequence [Just 1, Just 2]
Just [1,2]
GHCi> sequence [Just 1, Just 2, Nothing]
Nothing
The definition of sequence is equivalent to the following:
sequence [] = return []
sequence (m:ms) = do
x <- m
xs <- sequence ms
return (x:xs)
So we can expand the latter example as:
do x <- Just 1
xs <- do
y <- Just 2
ys <- do
z <- Nothing
zs <- return []
return (z:zs)
return (y:ys)
return (x:xs)
Using the do-notation expression of the monad laws, we can rewrite this as follows:
do x <- Just 1
y <- Just 2
z <- Nothing
return [x, y, z]
If you know how the Maybe monad works, you should now understand how sequence works to achieve the desired behaviour. :)
You can then compose this with foldr using (<$>) (from Control.Applicative; equivalently, fmap or liftM) to fold your binary function over the list:
GHCi> foldl' (+) 0 <$> sequence [Just 1, Just 2]
Just 3
Of course, you can use any fold you want, such as foldr, foldl1 etc.
As an extra, if you want the result to be Nothing when the list is empty, and thus be able to omit the zero value of the fold without worrying about errors on empty lists, then you can use this fold function:
mfoldl1' :: (MonadPlus m) => (a -> a -> a) -> [a] -> m a
mfoldl1' _ [] = mzero
mfoldl1' f (x:xs) = return $ foldl' f x xs
and similarly for foldr, foldl, etc. You'll need to import Control.Monad for this.
However, this has to be used slightly differently:
GHCi> mfoldl1' (+) =<< sequence [Just 1, Just 2]
Just 3
or
GHCi> sequence [Just 1, Just 2] >>= mfoldl1' (+)
Just 3
This is because, unlike the other folds, the result type looks like m a instead of a; it's a bind rather than a map.
As I understand it, you want to get the sum of a bunch of maybes or Nothing if any of them are Nothing. This is actually pretty simple:
maybeSum = foldl1 (liftM2 (+))
You can generalize this to something like:
f :: Monad m => (a -> a -> a) -> [m a] -> m a
f = foldl1 . liftM2
When used with the Maybe monad, f works exactly the way you want.
If you care about empty lists, you can use this version:
f :: MonadPlus m => (a -> a -> a) -> [m a] -> m a
f _ [] = mzero
f fn (x:xs) = foldl (liftM2 fn) x xs
What about something as simple as:
λ Prelude > fmap sum . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap sum . sequence $ [Just 1, Just 2, Nothing]
Nothing
Or, by using (+):
λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2]
Just 3
λ Prelude > fmap (foldr (+) 0) . sequence $ [Just 1, Just 2, Nothing]
Nothing
So, maybeSum = fmap sum . sequence.

Resources