Systematize and Complete the Coalton Collections Library #1329
Replies: 2 comments
-
Also, I think that some of the list functions could be more efficient if they used mutation internally, while still not "leaking" any mutability. For example, (I'm not going to fix this here, but I'll probably raise it as a separate issue.) |
Beta Was this translation helpful? Give feedback.
-
After more work, I think the originally proposed method of collection inheritance is going to introduce more complexity than I'd initially anticipated. Particularly, it will make working with LinearCollections less intuitive. The definitions: (define-class (Collection :m :a (:m -> :a))
...
(define-class (Collection :m (Tuple :k :v) => KeyedCollection :m :k :v (:m -> :k :v)))
...
(define-class (KeyedColleciton :m UFix :a => LinearCollection :m :a)
... run into some issues with wanting the Collection methods to be described inconsistently for KeyedCollections and LinearCollections. For example, take (filter (fn (key-value) (> (snd key-value) (fst key-value))) my-map) However, suppose you wanted to do something simple like remove all of the negative integers in a list of integres. You'd have to do something like this, because all LinearCollections are KeyedCollections with UFIx keys, which are in turn Collections of (UFix :a) tuples. (filter (fn (index-value) (>= (fst index-value) 0))) my-list) That's obviously untenable as a solution for the library. The obvious answer, if you want to maintain the class hierarchy, is to add a (filter-values (fn (index-value) (>= (fst index-value) 0))) my-list) And that's not so bad. The
For KeyedCollections, a more specialized and less commonly used datatype, all of these functions should exist. They are a more flexible datatype and they'll incur extra complexity for it. But, LinearCollections are the most used and should probably be the simplest of the types of Collections. One solution is to break the hierarchy up so that KeyedCollection and LinearCollection are both Collection instances, but LinearCollections are not KeyedCollection instances. A second solution is to break it up so that a LinearCollection is a KeyedCollection and a Collection, but a KeyedCollection and a Collection have no relationship. Either way, there are going to need to be some redundant functions defined. I'm currently leaning towards the second solution, because I imagine it would be useful in more scenarios to perform operations like splitting an ordered map than it would be to treat a map like a generic collection of tuples. |
Beta Was this translation helpful? Give feedback.
-
The current Coalton collections library suffers from several problems.
Here is a propsoal to standardize and complete the collections library, fixing the above problems:
COALTON-LIBRARY/COLLECTIONS/IMMUTABLE/
andCOALTON-LIBRARY/COLLECTIONS/MUTABLE/
packages. This mirrors the Scala organization, and it's very nice! Move packages likeCOALTON-LIBRARY/SLICE
which support the collections library to the rootCOALTON-LIBRARY/COLLECTIONS
package.remove-where
removes the first element that matches a predicate.remove-at
removes the element at an index.find-where
returns the first element matching a predicate.index-where
returns the index of the first element matching a predicate.contains-where?
returns a bool if you're matching a predicate, etc. Unfortunately this means discarding some of the historical Lisp functions likecar
, but those can remain specific to the List type in case anyone likes to use them!Ord-Map:insert :: ∀ :A :B. ORD :A ⇒ ((MAP :A :B) → :A → :B → (OPTIONAL (MAP :A :B)))
should be avoided, because the Optional return type only provides information, not safety, to the user at the expense of ergonomics. Another example, signatures likeList:take :: ∀ :A. (UFIX → (LIST :A) → (LIST :A))
should be favored overList:tail :: ∀ :A. ((LIST :A) → (OPTIONAL (LIST :A)))
. In both cases a reasonable return value can be constructed, and tail sacrifices ergonomics but gains neither safety nor information. Individual collections can have concrete functions that take this approach to support particular use-cases, but they shouldn't be on the generic interface.find-where odd? xs
, etc. Second, it's more useful with currying because that way you can thread collections through partially applied collection operations without needing to construct intermediate lambdas.Here are a few elements of the proposal I'm not sure about, and should definitely be discussed:
get
, etc, liberally. The current paradigm is to use the conventionfunction-unsafe
for those functions. I suggested use of the#
symbol (it's sharp, so it's pretty unsafe - it could poke an eye out!) instead for better ergonomics.get#
instead ofget-unsafe
,insert!#
instead ofinsert-unsafe!
, etc.Set
as an out-of-the-box default for the immutable set. But, you can importscala.collection.mutable.Set
and nowSet
creates a mutable set, and the compiler doesn't complain like Common Lisp's does.Finally, this is a big, breaking change - even for < 1.0 software like Coalton. It can be done in pieces:
Here is the proposed TypeClass hierarchy:
Collection :a
:a
elements.Monoid
,Applicative
,Functor
,Monad
,Traversable
ImmutableCollection :a
Collection :a
Set*
MutableCollection :a
Collection :a
MutSet*
KeyedCollection :k :v
Collection (Tuple :k :v)
ImmutableKeyedCollection :k :v
KeyedCollection :k :v
ImmutableCollection (Tuple :k :v)
Ord-Map
MutableKeyedCollection :k :v
KeyedCollection :k :v
MutableCollection (Tuple :k :v)
Hashmap
LinearCollection :a
KeyedCollection (Tuple UFix :a)
ImmutableLinearCollection :a
ImmutableKeyedCollection (Tuple UFix :a)
LinearCollection :a
Seq
,List
MutableLinearCollection :a
MutableKeyedCollection (Tuple UFix :a)
LinearCollection :a
Vector
,Queue
,Lisparray
(* - Set does not currently exsit)
Here is a chart showing the typeclass hierarchy along with the existing collections (plus mutable and immutable Sets):
Finally, because it's too big to include here, I've created a spreadsheet with the proposed functions and the status of the current collections. I'll continue to clean this up and add which typeclass each function should belong to.
Beta Was this translation helpful? Give feedback.
All reactions