I'm wondering how to obtain the unique values from a list by using Haskell list comprehension. So if I were to enter [2,4,5,4,4,6,2] it would return [2,4,5,6].
Initially I started with unique (y:ys) = [x | x <- (y:ys)] and I know I need some other condition on x, but am not sure how to get there.
The comment from #amalloy that list comprehensions are confined to a "local" perspective is the key insight here. There is a sensible way to write nub as a list comprehension, but you first need to change your perspective.
An often useful function sadly omitted from the library is the function which decorates each element of a list with its context.
picks :: [x] -> [([x], x, [x])]
picks [] = []
picks (x : xs) = ([], x, xs) : [(x : bs, y, as) | (bs, y, as) <- picks xs]
So
picks [1,2,3] =
[([],1,[2,3]), ([1],2,[3]), ([1,2],3,[])]
Each element of the list is put in the middle of a triple, with the elements 'before' to its left and the elements 'after' to its right.
This answer of mine explains the deep structure which makes picks in some sense a "standard" operation, derivable from the structure of lists. But we don't need that background information to deploy it.
The picks function gives us exactly the contextual information we need to write nub as a list comprehension. All we need to do is pick out the elements which don't occur in their own 'before lists'.
myNub :: Eq x => [x] -> [x]
myNub xs = [x | (bs, x, as) <- picks xs, not (elem x bs)]
I make no promises as to the efficiency of this operation, but I do like the clarity that comes from combining list comprehensions with extra spatial context.
You could do it in a (perhaps needlessly clever) way with laziness, by starting with a bit of circular reasoning: each element of the input should appear in the output, only if it hasn’t appeared in the output.
That is, for an input list like [0, 0, 1], the first 0 should be added but the second 0 should not.
Clearly, something like this won’t work:
unique xs = us
where us = [x | x <- xs, x `notElem` us]
Because it will get stuck in an infinite loop, trying to test elements of the output that haven’t been generated yet. What you can do instead is change the reasoning to this: each element of the input should appear in the output, only if it hasn’t already appeared in the output.
You can implement this directly by considering what “already” means: the current value must not have appeared at an index before the current index.
unique xs = catMaybes us
where
us =
[ if Just x `elem` take i us -- If the element has appeared before here
then Nothing -- then don’t include it again
else Just x -- otherwise do include it.
| (i, x) <- zip [0..] xs -- (Zip the elements with their indices.)
]
So for the input list xs = [0, 0, 1], this would generate xs' = [Just 0, Nothing, Just 1], which would be flattened by catMaybes into [0, 1]. Testing with QuickCheck confirms this is equivalent to nub, and halts because we only check the first take i elements of us at each step, ensuring that we don’t examine any elements that haven’t been generated yet.
It’s worth noting that, like nub, this is O(n2) in the length of the input.
Related
I'm trying to learn OCaml since I'm new to the language and I stumbled across this problem where I can't seem to find a way to see, in a function where I need to merge 2 kinds of these lists, if there is already an element with a key, and if so how to join the elements that come after. Would appreciate any guidance.
For example if I have:
l1: [(k, [e]); (ka, [])]
l2: [(k, [f; g])]
How can I end up with:
fl: [(k, [e; f; g]); (ka, [])]
Basically, how can I filter the key k from both lists while making their elements combine.
There are functions in the standard OCaml library for dealing with lists of pairs where the first element of each pair is a key. You will find them described here: https://ocaml.org/releases/4.12/api/List.html under Association lists.
I will repeat what #ivg says. This is not how you want to solve your problem if you have more than just a few pairs to work with.
First of all, using lists as mappings is a bad idea. It is much better to use dedicated data structures such as maps and hash tables.
Answering your question directly, you can concatenate two lists using the (#) operator, e.g.,
# [1;2;3] # [4;5;6];;
- : int list = [1; 2; 3; 4; 5; 6]
If you don't want repetitive elements when you merge then, and I feel like I repeat myself, it is bad to use lists for sets, it is better to use dedicated data structures such as sets and hash sets. But if you want to continue, then you can merge two lists without repetitions by checking if an element is already in the list before prepending to it. Easy to implement but hard to run, in a sense that it takes quadratic time to merge two lists this way.
If you still want to stick with the list of pairs, then you will find that the List.assoc function is useful, as it finds a value by key. The overall algorithm would be, given two lists, xs and ys, fold over elements of ys using xs as the initial value acc, and for each (ky,y) in ys if ky is already in acc, find the associated with ky value x and remove (List.remove_assoc) it, then merge x and y and prepend the merged value with the acc list, otherwise (if it is not in acc) just prepend (ky,y) to acc`. Note that this algorithm doesn't preserve order, so if it matters you need something more complex. Also, if your keys are sorted you can make it a little bit more efficient and easier to implement.
I guess you're doing this to practice with list.
What I would do is store the already found keys in an accumulator
let mergePairs yourList =
let rec aux accKeys = function
| [] -> []
| x :: xs -> let k,v = x in if (* k in accKeys *) then aux accKeys xs (*we suppress already
existing keys*)
else (k, v # (* get all the list of the other pairs with key = k in xs*))
:: aux (k::accKeys) xs
in aux [] yourList;;
I'm kinda new to Haskell and would like to know how to do the following:
L = [[1,2],[1,2,3],[1,2,3,4]]
How do I get rid of all the sub list ([1,2], [1,2,3]) and get a result of [[1,2,3,4]] only?
If I understood problem right, the solution can be like below:
import Data.List
-- Get only if element is not subsequence of any other x element
filterOutSublists x = filter (not . (isSub)) x
where
-- Check if given element is subsequence of any of x element
isSub y = foldl (\acc y' -> acc || (y `elem` (init $ subsequences y'))) False x
But this solution has very bad O(n) complexity, so it is useless for long lists.
You can use concat to flatten the sublists, then, since you want to get rid of the duplicates, you can use Data.Set to convert it to a set and back again to a list-
import qualified Data.Set as Set
f = (:[]) . Set.toList . Set.fromList . concat
Output
λ> f [[1,2],[1,2,3],[1,2,3,4]]
[[1,2,3,4]]
λ> f [[1, 2], [3, 4]]
[[1,2,3,4]]
Note that the final (:[]) is just there to put the final result inside a surrounding list, which is what you have shown in your example - though I don't quite know what even is the point of that.
If you want the results to be just one list instead of a list surrounded by another list, remove the (:[]) composition.
I am trying to understand this piece of code which returns the all possible combinations of [a] passed to it:
-- Infinite list of all combinations for a given value domain
allCombinations :: [a] -> [[a]]
allCombinations [] = [[]]
allCombinations values = [] : concatMap (\w -> map (:w) values)
(allCombinations values)
Here i tried this sample input:
ghci> take 7 (allCombinations [True,False])
[[],[True],[False],[True,True],[False,True],[True,False],[False,False]]
Here it doesn't seems understandable to me which is that how the recursion will eventually stops and will return [ [ ] ], because allCombinations function certainly doesn't have any pointer which moves through the list, on each call and when it meets the base case [ ] it returns [ [ ] ]. According to me It will call allCombinations function infinite and will never stop on its own. Or may be i am missing something?
On the other hand, take only returns the first 7 elements from the final list after all calculation is carried out by going back after completing recursive calls. So actually how recursion met the base case here?
Secondly what is the purpose of concatMap here, here we could also use Map function here just to apply function to the list and inside function we could arrange the list? What is actually concatMap doing here. From definition it concatMap tells us it first map the function then concatenate the lists where as i see we are already doing that inside the function here?
Any valuable input would be appreciated?
Short answer: it will never meet the base case.
However, it does not need to. The base case is most often needed to stop a recursion, however here you want to return an infinite list, so no need to stop it.
On the other hand, this function would break if you try to take more than 1 element of allCombination [] -- have a look at #robin's answer to understand better why. That is the only reason you see a base case here.
The way the main function works is that it starts with an empty list, and then append at the beginning each element in the argument list. (:w) does that recursively. However, this lambda alone would return an infinitely nested list. I.e: [],[[True],[False]],[[[True,True],[True,False] etc. Concatmap removes the outer list at each step, and as it is called recursively this only returns one list of lists at the end. This can be a complicated concept to grasp so look for other example of the use of concatMap and try to understand how they work and why map alone wouldn't be enough.
This obviously only works because of Haskell lazy evaluation. Similarly, you know in a foldr you need to pass it the base case, however when your function is supposed to only take infinite lists, you can have undefined as the base case to make it more clear that finite lists should not be used. For example, foldr f undefined could be used instead of foldr f []
#Lorenzo has already explained the key point - that the recursion in fact never ends, and therefore this generates an infinite list, which you can still take any finite number of elements from because of Haskell's laziness. But I think it will be helpful to give a bit more detail about this particular function and how it works.
Firstly, the [] : at the start of the definition tells you that the first element will always be []. That of course is the one and only way to make a 0-element list from elements of values. The rest of the list is concatMap (\w -> map (:w) values) (allCombinations values).
concatMap f is as you observe simply the composition concat . (map f): it applies the given function to every element of the list, and concatenates the results together. Here the function (\w -> map (:w) values) takes a list, and produces the list of lists given by prepending each element of values to that list. For example, if values == [1,2], then:
(\w -> map (:w) values) [1,2] == [[1,1,2], [2,1,2]]
if we map that function over a list of lists, such as
[[], [1], [2]]
then we get (still with values as [1,2]):
[[[1], [2]], [[1,1], [2,1]], [[1,2], [2,2]]]
That is of course a list of lists of lists - but then the concat part of concatMap comes to our rescue, flattening the outermost layer, and resulting in a list of lists as follows:
[[1], [2], [1,1], [2,1], [1,2], [2,2]]
One thing that I hope you might have noticed about this is that the list of lists I started with was not arbitrary. [[], [1], [2]] is the list of all combinations of size 0 or 1 from the starting list [1,2]. This is in fact the first three elements of allCombinations [1,2].
Recall that all we know "for sure" when looking at the definition is that the first element of this list will be []. And the rest of the list is concatMap (\w -> map (:w) [1,2]) (allCombinations [1,2]). The next step is to expand the recursive part of this as [] : concatMap (\w -> map (:w) [1,2]) (allCombinations [1,2]). The outer concatMap
then can see that the head of the list it's mapping over is [] - producing a list starting [1], [2] and continuing with the results of appending 1 and then 2 to the other elements - whatever they are. But we've just seen that the next 2 elements are in fact [1] and [2]. We end up with
allCombinations [1,2] == [] : [1] : [2] : concatMap (\w -> map (:w) values) [1,2] (tail (allCombinations [1,2]))
(tail isn't strictly called in the evaluation process, it's done by pattern-matching instead - I'm trying to explain more by words than explicit plodding through equalities).
And looking at that we know the tail is [1] : [2] : concatMap .... The key point is that, at each stage of the process, we know for sure what the first few elements of the list are - and they happen to be all 0-element lists with values taken from values, followed by all 1-element lists with these values, then all 2-element lists, and so on. Once you've got started, the process must continue, because the function passed to concatMap ensures that we just get the lists obtained from taking every list generated so far, and appending each element of values to the front of them.
If you're still confused by this, look up how to compute the Fibonacci numbers in Haskell. The classic way to get an infinite list of all Fibonacci numbers is:
fib = 1 : 1 : zipWith (+) fib (tail fib)
This is a bit easier to understand that the allCombinations example, but relies on essentially the same thing - defining a list purely in terms of itself, but using lazy evaluation to progressively generate as much of the list as you want, according to a simple rule.
It is not a base case but a special case, and this is not recursion but corecursion,(*) which never stops.
Maybe the following re-formulation will be easier to follow:
allCombs :: [t] -> [[t]]
-- [1,2] -> [[]] ++ [1:[],2:[]] ++ [1:[1],2:[1],1:[2],2:[2]] ++ ...
allCombs vals = concat . iterate (cons vals) $ [[]]
where
cons :: [t] -> [[t]] -> [[t]]
cons vals combs = concat [ [v : comb | v <- vals]
| comb <- combs ]
-- iterate :: (a -> a ) -> a -> [a]
-- cons vals :: [[t]] -> [[t]]
-- iterate (cons vals) :: [[t]] -> [[[t]]]
-- concat :: [[ a ]] -> [ a ]
-- concat . iterate (cons vals) :: [[t]]
Looks different, does the same thing. Not just produces the same results, but actually is doing the same thing to produce them.(*) The concat is the same concat, you just need to tilt your head a little to see it.
This also shows why the concat is needed here. Each step = cons vals is producing a new batch of combinations, with length increasing by 1 on each step application, and concat glues them all together into one list of results.
The length of each batch is the previous batch length multiplied by n where n is the length of vals. This also shows the need to special case the vals == [] case i.e. the n == 0 case: 0*x == 0 and so the length of each new batch is 0 and so an attempt to get one more value from the results would never produce a result, i.e. enter an infinite loop. The function is said to become non-productive, at that point.
Incidentally, cons is almost the same as
== concat [ [v : comb | comb <- combs]
| v <- vals ]
== liftA2 (:) vals combs
liftA2 :: Applicative f => (a -> b -> r) -> f a -> f b -> f r
So if the internal order of each step results is unimportant to you (but see an important caveat at the post bottom) this can just be coded as
allCombsA :: [t] -> [[t]]
-- [1,2] -> [[]] ++ [1:[],2:[]] ++ [1:[1],1:[2],2:[1],2:[2]] ++ ...
allCombsA [] = [[]]
allCombsA vals = concat . iterate (liftA2 (:) vals) $ [[]]
(*) well actually, this refers to a bit modified version of it,
allCombsRes vals = res
where res = [] : concatMap (\w -> map (: w) vals)
res
-- or:
allCombsRes vals = fix $ ([] :) . concatMap (\w -> map (: w) vals)
-- where
-- fix g = x where x = g x -- in Data.Function
Or in pseudocode:
Produce a sequence of values `res` by
FIRST producing `[]`, AND THEN
from each produced value `w` in `res`,
produce a batch of new values `[v : w | v <- vals]`
and splice them into the output sequence
(by using `concat`)
So the res list is produced corecursively, starting from its starting point, [], producing next elements of it based on previous one(s) -- either in batches, as in iterate-based version, or one-by-one as here, taking the input via a back pointer into the results previously produced (taking its output as its input, as a saying goes -- which is a bit deceptive of course, as we take it at a slower pace than we're producing it, or otherwise the process would stop being productive, as was already mentioned above).
But. Sometimes it can be advantageous to produce the input via recursive calls, creating at run time a sequence of functions, each passing its output up the chain, to its caller. Still, the dataflow is upwards, unlike regular recursion which first goes downward towards the base case.
The advantage just mentioned has to do with memory retention. The corecursive allCombsRes as if keeps a back-pointer into the sequence that it itself is producing, and so the sequence can not be garbage-collected on the fly.
But the chain of the stream-producers implicitly created by your original version at run time means each of them can be garbage-collected on the fly as n = length vals new elements are produced from each downstream element, so the overall process becomes equivalent to just k = ceiling $ logBase n i nested loops each with O(1) space state, to produce the ith element of the sequence.
This is much much better than the O(n) memory requirement of the corecursive/value-recursive allCombsRes which in effect keeps a back pointer into its output at the i/n position. And in practice a logarithmic space requirement is most likely to be seen as a more or less O(1) space requirement.
This advantage only happens with the order of generation as in your version, i.e. as in cons vals, not liftA2 (:) vals which has to go back to the start of its input sequence combs (for each new v in vals) which thus must be preserved, so we can safely say that the formulation in your question is rather ingenious.
And if we're after a pointfree re-formulation -- as pointfree can at times be illuminating -- it is
allCombsY values = _Y $ ([] :) . concatMap (\w -> map (: w) values)
where
_Y g = g (_Y g) -- no-sharing fixpoint combinator
So the code is much easier understood in a fix-using formulation, and then we just switch fix with the semantically equivalent _Y, for efficiency, getting the (equivalent of the) original code from the question.
The above claims about space requirements behavior are easily tested. I haven't done so, yet.
See also:
Why does GHC make fix so confounding?
Sharing vs. non-sharing fixed-point combinator
I want to generate all possible combinations of a 6 element list [x1,x2,x3,x4,x5,x6] with each xi being a number between 0 and 20.
I want to generate all possible combinations of such list, apply a function (takes the list as input and outputs a magical Int) to each list, then output the results to a list of tuples. So the list of tuples looks like
[([x11,x21,x31,x41,x51,x61],Int1), ([x12,x22,x32,x42,x52,x62],Int2), ...]
I tried to this by hand by quickly realised that there are too many combinations and it is practically impossible to do by hand.
The combinations are like [0,0,0,0,0,0], [1,7,0,10,11,6], [7,7,7,7,6,6], [20,20,20,20,20,20] and so on.
I know how to generate all combinations of a list and put them in a list of lists (because I asked this before)
foo [] = [[]]
foo (x:xs) = foo xs ++ map (x:) (foo xs)
What I want to achieve this time is different because I am not trying to generate the different combinations within a particular list, I am trying to generate all 6 element lists.
As far as I can tell, you want a cartesian product (denoted by × here) of 6 lists [0..20].
So essentially, something like this:
[0..20]×[0..20]×[0..20]×[0..20]×[0..20]×[0..20]
That's a lot of elements (85,766,121 to be exact). But, it could be done.
Perhaps an easier to understand version is as follows.
Let us define a function, cart, that would do something like a cartesian product over a list and a list of lists:
let cart xs ls = [x:l | x <- xs, l <- ls]
This function will take all elements from xs, and all elements from ls and build a list of lists with all possible concatenations.
Now, we need a base case. Suppose you wanted a list of lists of a single element instead of six. How would you apply our cart function? Well, since it adds each element from first argument to every element in second argument, we can pass a list of a single empty list as a second argument, and [0..20] as first argument:
cart [0..20] [[]]
We get
[[0],[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12],[13],[14],[15],[16],[17],[18],[19],[20]]
Great. Now we just apply it 6 times to its own result, starting with [[]]:
foldr ($) [[]] $ replicate 6 (cart [0..20])
($) is function application.
replicateM from Control.Monad (defined as sequence of n monadic actions: replicateM n x = sequence (replicate n x)) basically does the same when applied to lists (see e.g. Why does application of `sequence` on List of Lists lead to computation of its Cartesian Product? for why exactly that is) So shorter answer would be like this:
replicateM 6 [0..20]
You can map over those after this, e.g.
map (\x -> (x, magicFunction x)) $ replicateM 6 [0..20]
foo f xs = map (\ys -> (ys,f ys)) (replicateM (length xs) xs)
Here replicateM (length xs) xs will generate all combinations of the elements in xs. Then you just map over it.
Results in GHCI:
>import Control.Monad
>let foo f xs = map (\ys -> (ys,f ys)) (replicateM (length xs) xs)
>foo sum [1,2]
[([1,1],2),([1,2],3),([2,1],3),([2,2],4)]
ZipList comes with a Functor and an Applicative instance (Control.Applicative) but why not Alternative?
Is there no good instance?
What about the one proposed below?
Is it flawed?
is it useless?
Are there other reasonable possibilities (like Bool can be a monoid in two ways) and therefore neither should be the instance?
I searched for "instance Alternative ZipList" (with the quotes to find code first) and only found the library, some tutorials, lecture notes yet no actual instance.
Matt Fenwick said ZipList A will only be a monoid if A is (see here). Lists are monoids though, regardless of the element type.
This other answer by AndrewC to the same question discusses how an Alternative instance might look like. He says
There are two sensible choices for Zip [1,3,4] <|> Zip [10,20,30,40]:
Zip [1,3,4] because it's first - consistent with Maybe
Zip [10,20,30,40] because it's longest - consistent with Zip [] being discarded
where Zip is basically ZipList.
I think the answer should be Zip [1,3,4,40]. Let's see the instance:
instance Aternative Zip where
empty = Zip []
Zip xs <|> Zip ys = Zip (go xs ys) where
go [] ys = ys
go (x:xs) ys = x : go xs (drop 1 ys)
The only Zip a we can produce without knowing the type argument a is Zip [] :: Zip a, so there is little choice for empty. If the empty list is the neutral element of the monoid, we might be tempted to use list concatenation. However, go is not (++) because of the drop 1. Every time we use one entry of the first argument list, we drop one off the second as well. Thus we have a kind of overlay: The left argument list hides the beginning of the right one (or all of it).
[ 1, 3, 4,40] [10,20,30,40] [ 1, 3, 4] [ 1, 3, 4]
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | | | | | | | |
[ 1, 3, 4] | [10,20,30,40] []| | | [ 1, 3, 4]
[10,20,30,40] [ 1, 3, 4] [ 1, 3, 4] []
One intuition behind ziplists is processes: A finite or infinite stream of results. When zipping, we combine streams, which is reflected by the Applicative instance. When the end of the list is reached, the stream doesn't produce further elements. This is where the Alternative instance comes in handy: we can name a concurrent replacement (alternative, really), taking over as soon as the default process terminates.
For example we could write fmap Just foo <|> pure Nothing to wrap every element of the ziplist foo into a Just and continue with Nothing afterwards. The resulting ziplist is infinite, reverting to a default value after all (real) values have been used up. This could of course be done by hand, by appending an infinite list inside the Zip constructor. Yet the above is more elegant and does not assume knowledge of constructors, leading to higher code reusability.
We don't need any assumption on the element type (like being a monoid itself). At the same time the definition is not trivial (as (<|>) = const would be). It makes use of the list structure by pattern matching on the first argument.
The definition of <|> given above is associative and the empty list really is the empty element. We have
Zip [] <*> xs == fs <*> Zip [] == Zip [] -- 0*x = x*0 = 0
Zip [] <|> xs == xs <|> Zip [] == xs -- 0+x = x+0 = x
(fs <|> gs) <*> xs == fs <*> xs <|> gs <*> xs
fs <*> (xs <|> ys) == fs <*> xs <|> fs <*> ys
so all the laws you could ask for are satisfied (which is not true for list concatenation).
This instance is consistent with the one for Maybe: choice is biased to the left, yet when the left argument is unable to produce a value, the right argument takes over. The functions
zipToMaybe :: Zip a -> Maybe a
zipToMaybe (Zip []) = Nothing
zipToMaybe (Zip (x:_)) = Just x
maybeToZip :: Maybe a -> Zip a
maybeToZip Nothing = Zip []
maybeToZip (Just x) = Zip (repeat x)
are morphisms of alternatives (meaning psi x <|> psi y = psi (x <|> y) and psi x <*> psi y = psi (x <*> y)).
Edit: For the some/many methods I'd guess
some (Zip z) = Zip (map repeat z)
many (Zip z) = Zip (map repeat z ++ repeat [])
Tags / Indeces
Interesting. A not completely unrelated thought: ZipLists can be seen as ordinary lists with elements tagged by their (increasing) position index in the list. Zipping application joins two lists by pairing equally-indexed elements.
Imagine lists with elements tagged by (non-decreasing) Ord values. Zippery application would pair-up equally-tagged elements, throwing away all mismatches (it has its uses); zippery alternative could perform order-preserving left-preferring union on tag values (alternative on regular lists is also kind of a union).
This fully agrees with what you propose for indexed lists (aka ZipLists).
So yes, it makes sense.
Streams
One interpretation of a list of values is non-determinacy, which is consistent with the monad instance for lists, but ZipLists can be interpreted as synchronous streams of values which are combined in sequence.
With this stream interpretation it's you don't think in terms of the whole list, so choosing the longest stream is clearly cheating, and the correct interpretation of failing over from the first ZipList to the second in the definition <|> would be to do so on the fly as the first finishes, as you say in your instance.
Zipping two lists together doesn't do this simply because of the type signature, but it's the correct interpretation of <|>.
Longest Possible List
When you zip two lists together, the result is the minimum of the two lengths. This is because that's the longest possible list that meets the type signature without using ⊥. It's a mistake to think of this as picking the shorter of the two lengths - it's the longest possible.
Similarly <|> should generate the longest possible list, and it should prefer the left list. Clearly it should take the whole of the left list and take up the right list where the left left off to preserve synchronisation/zippiness.
Your instance is OK, but it does something ZipList doesn't by
(a) aiming for the longest list, and
(b) mixing elements between source lists.
Zipping as an operation stops at the length of the shortest list.
That's why I concluded in my answer:
Thus the only sensible Alternative instance is:
instance Alternative Zip where
empty = Zip []
Zip [] <|> x = x
Zip xs <|> _ = Zip xs
This is consistent with the Alternative instances for Maybe and parsers that say you should do a if it doesn't fail and go with b if it does. You can say a shorter list is less successful than a longer one, but I don't think you can say a non-empty list is a complete fail.
empty = Zip [] is chosen because it has to be polymorphic in the element type of the list, and the only such list is []
For balance, I don't think your instance is terrible, I think this is cleaner, but hey ho, roll your own as you need it!
There is in fact a sensible Alternative instance for ZipList. It comes from a paper on free near-semirings (which MonadPlus and Alternative are examples of):
instance Alternative ZipList where
empty = ZipList []
ZipList xs <|> ZipList ys = ZipList $ go xs ys where
go [] bs = bs
go as [] = as
go (a:as) (_:bs) = a:go as bs
This is a more performant version of the original code for it, which was
ZipList xs <|> ZipList ys = ZipList $ xs ++ drop (length xs) ys
My guiding intuition for Alternative comes from parsers which suggest that if one branch of your alternative fails somehow it should be eradicated thus leading to a Longest-style Alternative that probably isn't terrifically useful. This would be unbiased (unlike parsers) but fail on infinite lists.
Then again, all they must do, as you suggest, is form a Monoid. Yours is left biased in a way that ZipList doesn't usually embody, though—you could clearly form the reflected version of your Alternative instance just as easily. As you point out, this is the convention with Maybe as well, but I'm not sure there's any reason for ZipList to follow that convention.
There's no sensible some or many I don't believe, although few Alternatives actually have those—perhaps they'd have been better isolated into a subclass of Alternative.
Frankly, I don't think your suggestion is a bad instance to have, but I don't have any confidence about it being "the" alternative instance implied by having a ZipList. Perhaps it'd be best to see where else this kind of "extension" instance could apply (trees?) and write it as a library.