Generalize `filterM` (etc.?) to `Applicative`
glebec opened this issue · 3 comments
Today I noticed that PureScript filterM is constrained to Monad, whereas Haskell filterM is constrained to Applicative. After looking at the source code for each and asking on FP Slack, it seems there is no particular reason filterM cannot be more general in PS.
#35 was set to change this and some other things (e.g. replicateM). However, that PR was closed due to staleness. The author @DavidHarrison was going to split it up into individual PRs, but hasn't gotten around to it yet. It seems worthwhile to double-check that PR to see if there is anything else from it you may want to merge.
I would like to do what we did in the arrays library: provide a new filterA, and continue to provide filterM as a alias for filterA, together with a deprecation warning, until the next major release.
A reason not to do that, at least for lazy lists, is demonstrated by one of the tests:
assert $ filterM (const Nothing) (repeat 0) == NothingSince our apply is strict in both of its arguments, a filterA would not be able to terminate on this example, since there's no way to conditionally recurse based on the f Boolean value. If our apply were a little more scalazesque and had type forall a. f (a -> b) -> (Unit -> f a) -> f b, then we could do it, but that would be a pretty big change! (Besides, I'm sure there are reasons PS favors strict classes; it must have come up before with Semigroup or HeytingAlgebra or something.)
We could still introduce filterA for strict lists, or even also for lazy lists with a caution that it forces the whole list. But deprecating filterM in favor of filterA doesn't make sense, probably even for strict lists; I don't think we'd want the strict and lazy interfaces to diverge in that way, right?
I think adding a filterA that is strict (and explains @rhendric's comment above) without deprecating filterM is how this issue should proceed.