silver icon indicating copy to clipboard operation
silver copied to clipboard

Using type classes

Open krame505 opened this issue 5 years ago • 9 comments

Meta-bug to keep track of all the things that we want to change in the standard library once type classes are finished. Some of these are partially doable now and some depend on attribute occurrence constraints.

  • [x] Eq typeclass
    • [x] Non-by functions (contains, lookup, union, etc.)
    • [x] Make == forward to calling eq
    • [x] Default instance with isEqual/isEqualTo equality attributes
    • [x] Refactor Silver equality testing extension
  • [x] Ord typeclass
    • [x] Non-by functions (sort, etc.)
    • [x] Make relational operators forward to member functions
    • [x] Default instance based on attributes - introduce "ordering attributes" like equality attrs, but using < instead?
  • [x] Convertible typeclass with toInteger, toFloat, toString, and toBoolean, with instances implemented foreign functions
  • [x] Monoid type class
    • [x] Allow default of monoid attributes to be inferred
  • [x] Functor/Applicative/Monad/MonadFail hierarchy
    • [x] Fix do-notation
    • [x] Refactor implicit monad extension (Dawn?)
  • [x] Show type class with pp :: (Document ::= a)
    • Have show :: Show a => (String ::= Integer a)
    • Default instance for pp attribute (instance pp {} occurs on a => Show a)
    • Instance for Show Document where pp = id
  • [ ] Category type class
  • [x] Arbitrary type class for randomized testing, resurrect/refactor treegen extension
  • [x] Make deserialize and rewriteWith be library functions with reifyable (typeable?) constraint
  • [ ] Refactor origins using a tracked constraint
  • [x] Refactor standard lib with https://github.com/melt-umn/silver/pull/451

krame505 avatar Dec 29 '20 04:12 krame505

Since unlike Haskell we don't have infix operator functions in Silver, what should the equivalents of <*, *> and <*> for the Applicative type class be named?

@remexre any suggestions?

krame505 avatar Jan 20 '21 22:01 krame505

not 2 be wrong but we could just add <*, *>, <*>, <$>, >>=, =<<, >>>, <<<, <=<, >=>, <$, $> as valid names :eyes: (I think these are all the ones I've ever actually used)

for names for the ones you listed, purescript names them ap, applyFirst, and applySecond; I've already got them written up into silver here

remexre avatar Jan 20 '21 22:01 remexre

I'm vetoing non-alphanumeric function names (and I'm sure Eric would if I didn't :-P)

Those names seem reasonable.

What's the reason for the seperate Apply and Bind type classes in your library, though? That seems somewhat nonstandard? (I've been mainly referencing Haskell and Idris, btw.)

krame505 avatar Jan 20 '21 23:01 krame505

I've been using PureScript as inspiration. As I understand it, they split them up to reduce the number of laws per typeclass; there might be something in their effect system('s history) that made them want to separate Bind from Applicative though, I'm not sure.

IMO PureScript's break-up of typeclasses is better-designed than Haskell's, though this is mainly because they can remove historical warts (sequenceA), and they split up Num as algebra does.

remexre avatar Jan 20 '21 23:01 remexre

Counterexamples of Type Classes gives the following examples:

An Apply which is not an Applicative

The constant functor data Const k a = Const k can be made into an Apply (but not an Applicative) whenever k is an instance of Semigroup (but not Monoid).

A Bind which is not a Monad

The Map k data type has an implementation of Bind, since we can implement the map, apply and bind functions, but fails to be a Monad, since we cannot implement pure :: forall k a. a -> Map k a such that the monad laws will hold.

To me the, "keep typeclasses with as few laws as possible" seems the stronger argument, but /shrug

remexre avatar Jan 21 '21 03:01 remexre

I see your point, but a potential counterargument is that with the PureScript approach, to define a new instance of Monad, I would need to define instances for 5 classes, which seems like it could be too much.

krame505 avatar Jan 21 '21 04:01 krame505

well, my answer to that one is deriving strategies: you should only have to write the applicative and monad instances, and the others can be derived with the helpers in the appropriate modules.

remexre avatar Jan 21 '21 04:01 remexre

I guess this depends somewhat on how much work we want to do with the functor/applicative/monad hierarchy. I wasn't intending to do much with these besides reworking do notation and enabling us to clean up the hard-coded handling in the implicit monads extension. But this is maybe something we can discuss at our meeting tomorrow.

krame505 avatar Jan 21 '21 04:01 krame505

sure; I'd like to go as far as ApplicativeDo, because Validated would be kinda nice... though, maybe equation-level case statements would serve the same purpose (of not having cases in a bunch of attributes + partiality when no value is appropriate).

(Oh, and looks like Scala's cats does the same thing, wrt having a separate Apply and FlatMap trait.)

remexre avatar Jan 21 '21 17:01 remexre