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.
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.
I'm trying to define map in ghci recursively. What I've come up with so far is the following:
let mymap f (x:xs) = if null xs then [] else f x : map f xs
What I'd like to do now is to simplify it a bit and hardcode the list inside the code, i.e., write a map function which takes a function as argument and does what the real map does but only to a specific list e.g., [1, 2, 3, 4, 5].
Is such a thing possible?
First of all, your map function isn't entirely correct. If I were to input mymap (+1) [1], I would expect to get [2] back, but instead I'd get []. If I tried mymap (+1) [], my program would crash on a pattern match failure, since you haven't defined that case. Instead, consider defining your mymap as
mymap :: (a -> b) -> [a] -> [b]
mymap f [] = []
mymap f (x:xs) = f x : mymap f xs
If you want to do it inline with an if statement then you'd have to do
mymap f xs = if null xs then [] else f (head xs) : mymap f (tail xs)
These do essentially the same thing, but the first is a bit easier to read in my opinion.
If you want to use mymap to define a function that maps only over a specific list, you could do so pretty easily as
mapOnMyList :: (Int -> b) -> [b]
mapOnMyList f = mymap f [1, 2, 3, 4, 5]
Or in point-free form
mapOnMyList = (`mymap` [1, 2, 3, 4, 5])
using mymap as an infix operator. This is equivalent to flip mymap [1, 2, 3, 4, 5], but the operator form is usually preferred since flip is not necessarily free to execute.
You can also do this using list comprehensions:
mymap f xs = [f x | x <- xs]
Or if you want to hard code the list
mapOnMyList f = [f x | x <- [1, 2, 3, 4, 5]]
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 (+))
I was playing with Haskell and ghci when I found this which really bothers me:
foldl (++) [[3,4,5], [2,3,4], [2,1,1]] []
I expected to get this: [3,4,5,2,3,4,2,1,1]
However it gets:
[[3,4,5],[2,3,4],[2,1,1]]
As far as I understand foldl, it should be this:
(([] ++ [3, 4, 5]) ++ [2, 3, 4]) ++ [2, 1, 1]
If I type this in ghci it really is [3,4,5,2,3,4,2,1,1].
And the other strange thing is this:
Prelude> foldl1 (++) [[3,4,5], [2, 3, 4], [2, 1, 1]]
[3,4,5,2,3,4,2,1,1]
I expect foldl and foldl1 to behave in the same way. So what does foldl actually do?
The order of arguments is wrong. The right one is:
foldl (++) [] [[3,4,5], [2,3,4], [2,1,1]]
(That is, first the accumulator, then the list.)
You switched the arguments around. foldl takes the accumulator's starting value first, then the list to fold. So what happens in your case is that foldl folds over the empty list and thus returns the starting value, which is [[3,4,5], [2, 3, 4], [2, 1, 1]]. This will do what you want:
foldl (++) [] [[3,4,5], [2, 3, 4], [2, 1, 1]]
You got the argument order wrong
Prelude> :t foldl
foldl :: (a -> b -> a) -> a -> [b] -> a
Prelude> :t foldl1
foldl1 :: (a -> a -> a) -> [a] -> a
The initial value comes first. In your case, your initial value was [[3,4,5],[2,3,4],[2,1,1]] and you folded over the empty list, so you got back the initial value.