Open milesfrain opened 3 years ago
I'll take a look at the functions, bit by bit, starting with the Lazy Basic
category, i.e. the things missing from NonEmpty
. I'll update this comment later with the other categories as well.
Are you looking to implement these functions specifically for NonEmptyList
? Or for NonEmpty a f
in general (maybe with some constraints on f
)? I noticed these function generally do exist for NonEmptyArray
which would suggest the former.
NonEmpty
... or could make sense, taking NonEmpty
and returning a basic List
, similarly to what filter
does.
range
difference
delete
deleteAt
deleteBy
null
slice
NonEmpty
Pattern(..)
+ stripPrefix
, and alterAt
could work with a little change in semantics (returning Nothing
in cases we delete the last element from our NonEmpty
)insert
insertBy
many
some
transpose
Why are the functions implemented for specific types rather than only once per typeclass, by the way? My students are frequently frustrated — in the best case scenario having to sift through tens of different length
functions in the autocomplete window, or more commonly having to suffer a "weird type error" as a consequence of importing the incorrect one.
What I (and they) would expect is having only one length
in Data.Foldable
(and Foldable1
), for example. The same with map
, filter
and fold
.
Thanks for digging into this.
Are you looking to implement these functions specifically for
NonEmptyList
? Or forNonEmpty a f
in general?
Planning on implementing specifically for NonEmptyList
.
Doesn't make sense with
NonEmpty
... or could make sense, takingNonEmpty
and returning a basicList
, similarly to whatfilter
does.
I think range
should be able to return NonEmptyList
, at least that works for Array.NonEmpty.range
.
For the others, I'm leaning towards returning a basic List
. Here are some more examples of that behavior from CommonDiffEmptiability
in #199 (assume c
is NonEmptyList
and canEmpty
is List
):
catMaybes :: forall a. c (Maybe a) -> canEmpty a
drop :: forall a. Int -> c a -> canEmpty a
dropWhile :: forall a. (a -> Boolean) -> c a -> canEmpty a
filter :: forall a. (a -> Boolean) -> c a -> canEmpty a
filterM :: forall m a. Monad m => (a -> m Boolean) -> c a -> m (canEmpty a)
mapMaybe :: forall a b. (a -> Maybe b) -> c a -> canEmpty b
partition :: forall a. (a -> Boolean) -> c a -> { no :: canEmpty a, yes :: canEmpty a }
span :: forall a. (a -> Boolean) -> c a -> { init :: canEmpty a, rest :: canEmpty a }
take :: forall a. Int -> c a -> canEmpty a
takeEnd :: forall a. Int -> c a -> canEmpty a
takeWhile :: forall a. (a -> Boolean) -> c a -> canEmpty a
Does make sense with
NonEmpty
Your alterAt
proposal looks good and matches Array.NonEmpty.alterAt
. Your other proposals look good too.
Why are the functions implemented for specific types rather than only once per typeclass, by the way? My students are frequently frustrated — in the best case scenario having to sift through tens of different
length
functions in the autocomplete window, or more commonly having to suffer a "weird type error" as a consequence of importing the incorrect one.What I (and they) would expect is having only one
length
inData.Foldable
(andFoldable1
), for example. The same withmap
,filter
andfold
.
I've also wondered why we don't make more use of typeclasses, but have read that this can lead to more issues later on. Some more discussion (and links to other related info) can be found in #184.
For the "weird type error", I'm guessing these are Could not unify type List with List
. https://github.com/purescript/purescript/issues/1647 is tracking proposals to improve those error messages.
Here's a patched API proposal:
Instances:
-----
Basic NonEmpty Lazy LazyNonEmpty
(all)
-----
Alt
Applicative
Apply
Bind
Eq
Eq1
Extend
Foldable
FoldableWithIndex
Functor
FunctorWithIndex
Monad
Ord
Ord1
Semigroup
Show
Traversable
TraversableWithIndex
Unfoldable1
-----
Basic Lazy
(only canEmpty)
-----
Alternative
MonadPlus
MonadZero
Monoid
Plus
Unfoldable
-----
NonEmpty LazyNonEmpty
(only NonEmpty)
-----
Comonad
Foldable1
Traversable1
-----
Basic NonEmpty
(only strict)
-----
Note that there are no typeclasses exclusive to strict (non-Lazy) lists
-----
Lazy LazyNonEmpty
(only Lazy)
-----
Lazy
-----
NonEmpty Lazy LazyNonEmpty
(non-Basic)
-----
Newtype
Functions:
-----
Basic NonEmpty Lazy LazyNonEmpty
(all)
-----
alterAt
appendFoldable
catMaybes
concat
concatMap
cons
cons'
delete
deleteAt
deleteBy
(\\), difference
drop
dropEnd
dropWhile
elemIndex
elemLastIndex
filter
filterM
findIndex
findLastIndex
foldM
fromFoldable
group
groupAll
groupAllBy
groupBy
head
(!!), index
init
insert
insertAt
insertBy
intersect
intersectBy
last
length
mapMaybe
modifyAt
nub
nubBy
nubByEq
nubEq
partition
Pattern(..)
(..), range
reverse
singleton
slice
snoc
snoc'
some
someRec
sort
sortBy
span
stripPrefix
tail
take
takeEnd
takeWhile
toUnfoldable
transpose
uncons
union
unionBy
unsnoc
unzip
updateAt
zip
zipWith
zipWithA
-----
Basic Lazy
(only canEmpty)
-----
null
many
manyRec
-----
NonEmpty LazyNonEmpty
(only NonEmpty)
-----
fromList
toList
-----
Lazy LazyNonEmpty
(only Lazy)
-----
iterate
repeat
cycle
foldrLazy
scanlLazy
replicate1 (specialized from Unfoldable1's replicate1)
replicate1M (specialized from Unfoldable1's replicate1A)
-----
Lazy
-----
replicate (specialized from Unfoldable's replicate)
replicateM (specialized from Unfoldable's replicateA)
Summary of changes:
All functions that were previously available to BOTH Lazy
and NonEmpty
lists are now available to LazyNonEmpty
list.
Added to Lazy and LazyNonEmpty
--------------
sort
sortBy
unsnoc
replicate1
replicate1M
Added to Basic and Lazy
--------------
appendFoldable
Added to Basic and LazyNonEmpty
--------------
cons
Added to LazyNonEmpty
--------------
cycle
foldrLazy
scanlLazy
Added to NonEmpty and LazyNonEmpty
--------------
(..), range
(\\), difference
Pattern(..)
alterAt
delete
deleteAt
deleteBy
insert
insertBy
slice
some
stripPrefix
transpose
Added to NonEmpty, Lazy, and LazyNonEmpty
--------------
dropEnd
takeEnd
cons'
snoc'
someRec
Questions:
Should cons'
and snoc'
be available to all list types? Considering these signatures:
cons' :: forall a. a -> List a -> NonEmptyList a -- existing for NonEmpty
cons' :: forall a. a -> NonEmptyList a -> List a -- new for Basic
Is it correct to assume that the many*
functions are incompatible with NonEmpty
, and that the *Rec
functions are compatible with everything, including Lazy
? Would the *Rec
functions be useful in the Array
library?
Should specialized versions of replicate1
/replicate1M
be available for both Lazy
and LazyNonEmpty
? Argument for is that this matches availability of non-specialized versions. Argument against is that I can't think of a reason to use replicate1
instead of replicate
for Lazy
.
Should List
have specialized versions of scanl
/scanr
, like Array
? It looks like List
currently relies on Traversable
for these functions.
Should there be a toUnfoldable1
function (similar to toUnfoldable
) for NonEmpty
lists?
See https://github.com/purescript/purescript-lists/issues/183#issuecomment-825460643 for a proposed API
It looks like there are a few missing
functions
andinstances
across the different list modules in this library. To tackle this more systematically, I found the contents of each of the cells of a 4-way Venn diagram created by comparing the following modules:I've only looked over the
instances
so far. These appear to be the gaps:Lazy
missing fromLazyNonEmptyList
Eq1
,Ord1
missing fromNonEmptyList
,LazyNonEmptyList
Foldable1
,Traversable1
missing fromLazyNonEmptyList
Here are some notes on the remaining differences, which appear to be fine:
*NonEmptyList
Comonad
is only in*NonEmptyList
, since you can'textract
something from an empty list.Newtype
convenience wrapper.I still need to look through the
functions
. Feel free to help me flag or dismiss any of those differences.Here's a brief explanation of how to read an entry in the listing of cells. For example in this entry:
It means that
Comonad
appears only inLazyNonEmpty
andNonEmpty
, but not in any other modules. More specifically,Comonad
is the output of:This diagram might help with visualizing the "cells":
Here's the full listing (empty cells omitted).
Instances:
Functions: