2

I have read some of this post Meaning of Alternative (it's long)

What lead me to that post was learning about Alternative in general. The post gives a good answer to why it is implemented the way it is for List.

My question is:

  • Why is Alternative implemented for List at all?

Is there perhaps an algorithm that uses Alternative and a List might be passed to it so define it to hold generality?

I thought because Alternative by default defines some and many, that may be part of it but What are some and many useful for contains the comment:

To clarify, the definitions of some and many for the most basic types such as [] and Maybe just loop. So although the definition of some and many for them is valid, it has no meaning.

In the "What are some and many useful for" link above, Will gives an answer to the OP that may contain the answer to my question, but at this point in my Haskelling, the forest is a bit thick to see the trees.

Thanks

user49011
  • 523
  • 1
  • 3
  • 10
  • Why *avoid* implementing it? – Daniel Wagner Dec 11 '21 at 02:52
  • @DanielWagner I don't know whether to call you a wise guy or an old sage but that seems to point to my thought about generality. There must be an acronym/saying somewhere about unnecessarily multiplying implementations. Thanks! – user49011 Dec 11 '21 at 03:12

3 Answers3

2

There's something of a convention in the Haskell library ecology that if a thing can be an instance of a class, then it should be an instance of the class. I suspect the honest answer to "why is [] an Alternative?" is "because it can be".

...okay, but why does that convention exist? The short answer there is that instances are sort of the one part of Haskell that succumbs only to whole-program analysis. They are global, and if there are two parts of the program that both try to make a particular class/type pairing, that conflict prevents the program from working right. To deal with that, there's a rule of thumb that any instance you write should live in the same module either as the class it's associated with or as the type it's associated with.

Since instances are expected to live in specific modules, it's polite to define those instances whenever you can -- since it's not really reasonable for another library to try to fix up the fact that you haven't provided the instance.

Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
  • Terrific! An old sage indeed. I am better when I know the whys, and your answer showed me whys, deeper than the question asked. – user49011 Dec 11 '21 at 03:35
  • Thanks for this explanation. I wanted to include something about Haskell's philosophy that instances should exist where possible, but I didn't know why that was the philosophy. – amalloy Dec 11 '21 at 03:46
  • 1
    I agree, but I'd remark that this convention applies only when there is only _one_ "reasonable" instance. I mean, we can write `instance Monoid Int`, but there are many ways to do it, so we don't have such an instance in the libraries. We instead have `Sum`, `Max`, ... newtype wrappers for the several options. – chi Dec 11 '21 at 11:09
1

Alternative is useful when viewing [] as the nondeterminism-monad. In that case, <|> represents a choice between two programs and empty represents "no valid choice". This is the same interpretation as for e.g. parsers.

some and many does indeed not make sense for lists, since they try iterating through all possible lists of elements from the given options greedily, starting from the infinite list of just the first option. The list monad isn't lazy enough to do even that, since it might always need to abort if it was given an empty list. There is however one case when both terminates: When given an empty list.

Prelude Control.Applicative> many []
[[]]
Prelude Control.Applicative> some []
[]

If some and many were defined as lazy (in the regex sense), meaning they prefer short lists, you would get out results, but not very useful, since it starts by generating all the infinite number of lists with just the first option:

Prelude Control.Applicative> some' v = liftA2 (:) v (many' v); many' v = pure [] <|> some' v
Prelude Control.Applicative> take 100 . show $ (some' [1,2])
"[[1],[1,1],[1,1,1],[1,1,1,1],[1,1,1,1,1],[1,1,1,1,1,1],[1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1],[1,1,1,1,1,"

Edit: I believe the some and many functions corresponds to a star-semiring while <|> and empty corresponds to plus and zero in a semiring. So mathematically (I think), it would make sense to split those operations out into a separate typeclass, but it would also be kind of silly, since they can be implemented in terms of the other operators in Alternative.

Hjulle
  • 2,471
  • 1
  • 22
  • 34
0

Consider a function like this:

fallback :: Alternative f => a -> (a -> f b) -> (a -> f e) -> f (Either e b)
fallback x f g = (Right <$> f x) <|> (Left <$> g x)

Not spectacularly meaningful, but you can imagine it being used in, say, a parser: try one thing, falling back to another if that doesn't work.

Does this function have a meaning when f ~ []? Sure, why not. If you think of a list's "effects" as being a search through some space, this function seems to represent some kind of biased choice, where you prefer the first option to the second, and while you're willing to try either, you also tag which way you went.

Could a function like this be part of some algorithm which is polymorphic in the Alternative it computes in? Again I don't see why not. It doesn't seem unreasonable for [] to have an Alternative instance, since there is an implementation that satisfies the Alternative laws.

As to the answer linked to by Will Ness that you pointed out: it covers that some and many don't "just loop" for lists. They loop for non-empty lists. For empty lists, they immediately return a value. How useful is this? Probably not very, I must admit. But that functionality comes along with (<|>) and empty, which can be useful.

amalloy
  • 89,153
  • 8
  • 140
  • 205
  • to clarify, [this answer](https://stackoverflow.com/a/7681283/849891) really discusses the `[]` instance's `many` and `some` closely. (perhaps that's the one you meant). – Will Ness Dec 11 '21 at 09:20