purescript/purescript-strings

Consider moving orphan instance monoidString into purescript-monoid?

hdgarrood opened this issue · 25 comments

Since the String type comes from the Prim module, if we assume that Monoid should stay in 'userland', the only option to avoid having an orphan instance for Monoid String would be to move it into purescript-monoid.

I'm happy to put PRs together for this if you agree.

This was only just reversed recently actually, so that purescript-monoid could be moved into a better place in the dependency hierarchy. We have a similar situation with Array also, there's a whole bunch of orphan instances in purescript-arrays.

Ah, ok then. If orphan instances are acceptable, then I guess I will need to handle orphans in psc-docs etc in purescript/purescript#1067? Currently, in that branch, all instances are grouped under their related classes and types, like Haddock does - orphan instances don't appear in the output at all.

I would rather not have orphans at all, but the current choice is to have data modules depending on class modules, so strings depends on monoids and the Monoid instance goes in strings. I think the only way to get rid of orphans would be to change to class modules depending on data modules.

I hadn't thought about the fact I was making an orphan when I moved it over actually. Orphans are really not awesome, but the Prim types do make it a little awkward... maybe this should go back to Monoid afterall.

I used to not care quite so much, but the psc-docs changes (which are a good thing) make me care about orphan instances now :)

Avoiding orphans would also mean moving the Functor...Monad instances for Array into the prelude.

Avoiding orphans would also mean moving the Functor...Monad instances for Array into the prelude.

Which I actually think we should do anyway, especially if we're removing special support for arrays. I might even argue for moving [] out of Prim and into purescript-arrays.

Edit: sorry, I mean, I think we should move the type into arrays.

Would it be possible to move the Array / [] type into purescript-arrays and still allow the compiler to understand array literals, ie [1,2,3]?

I'm actually in favor of removing array literals, which might seem drastic, but I think there really are very few cases where you want to just dump an array literal (which can't be constructed neatly otherwise) into code. The only case I can think of is something like a cipher or protocol.

Edit: to be clear, I want it to be completely clear that we have better tools and arrays are for low-level interop only.

How about... all of the Halogen HTML DSL?

Well that would probably change to use List, and we could still use : or <> to construct lists.

Ideally, [1,2,3] would mean Cons 1 (Cons 2 (Cons 3 Nil))), but I don't think that's an option sadly.

Hmm, I think that would make things pretty annoying:

icon :: forall p i. H.HTML p i
icon = H.div [ A.classes [ B.colXs1, Vc.navIcon ] ]
             [ H.a [ A.href homeHash
                   , A.classes [B.navbarBrand, Vc.logo]
                   ]
                   [ glyph B.glyphiconFolderOpen ]
             ]

Would become something like:

icon :: forall p i. H.HTML p i
icon = H.div ( A.classes (B.colXs1 : Vc.navIcon : Nil) : Nil )
             ( H.a ( A.href homeHash
                   : A.classes (B.navbarBrand : Vc.logo : Nil)
                   : Nil
                   )
                   (glyph B.glyphiconFolderOpen : Nil)
             : Nil
             )

(and I probably made a mistake somewhere in there)

It's already quite laborious to write compared with HTML or virtual-dom/h.

It's not ideal, I agree. But, I can't find a way to reconcile "arrays are low-level, don't use them" with "we have syntactic support for arrays".

In the Halogen case, we could go the blaze-html route:

icon :: forall p i. H.HTML p i
icon = H.div (A.classes (B.colXs1 <> Vc.navIcon))
             (H.a (A.href homeHash
                   <> A.classes (B.navbarBrand <> Vc.logo))
                   (glyph B.glyphiconFolderOpen))

(HTML represents a list of VTree nodes)

Wouldn't removing pattern matching be enough? That would prevent the biggest misuse of them, encouraging use of folds instead.

I think if we remove the type syntax and pattern matching,that should hopefully discourage people from using them. We probably also need a better list implementation in core. Removing array literals is drastic, and reduces expressivity - I just worry that people will continue to abuse arrays.

Why is [1,2,3] becoming Cons 1 (Cons 2 (Cons 3 Nil)) not an option?

One use case for array literals is defining a bunch of test data. I don't have a PureScript example to hand but I do have a Haskell one: https://github.com/hdgarrood/bower-json/blob/master/test/Main.hs

It's also nice to have almost-literals for other array-like types by applying toList, toSeq, etc. to an array literal.

I don't see the problem with array patterns which don't involve : - for example, patterns like [], or [a,b,c]. These have been quite handy for writing FromJSON instances for me in the past, see https://github.com/hdgarrood/multipac/blob/master/src/Types.purs#L501 (the encoding is a bit perverse, but I wanted to make the payloads as small as possible because there are up to 30 of them going back and forth every second).

Ok, let's keep array literals and patterns then, remove : and :-patterns and [] type syntax, move : into purescript-arrays. We'll have to keep Array in Prim and suffer the orphan instance, but that's fine.

suffer the orphan instance

Why not add array instances for prelude type classes to the prelude? Would that make it too complex?

That's certainly an option. I think I'd prefer the alternative though.

Even if it meant that the Functor...Monad instances for Array wouldn't show up anywhere in pursuit documentation?

Thinking about this a little more:

The choice of data modules depending on class modules necessitates instances going into the data module (since defining an instance requires knowledge of both the class and the type). This only seems to be an issue for those data types which come from the Prim module. We don't want to put anything inside Prim other than just the five edit: six primitive types: Function, Object, Array, String, Number, Boolean.

Therefore, what if we continue with the current approach of data modules depending on class modules, except for instances of these types, which should go into the same module as the class? This is already the case for Number, Function, and Boolean, as far as I can tell.

That would be my preference - instances for all Prim type declared with the classes.

That seems like a better option than instances-with-data - which would be a massive change - even if the latter would be more principled

Even though I was the one who originally broke that scheme with this Monoid String change :)

Cool - subsumed by purescript/purescript#1076 then, I guess?