purescript-concur / purescript-concur-react

Concur UI Framework for Purescript
https://purescript-concur.github.io/purescript-concur-react
MIT License
269 stars 17 forks source link

Discussion: making HTML a typeclass #14

Open bbarker opened 5 years ago

bbarker commented 5 years ago

I was thinking of creating a small CSS wrapper library for Prism.CSS and Concur. This may or may not be a good idea - too early to tell. But, it made me realize that HTML might be better off as a typeclass with all the element functions as typeclass members, because libraries that depend on HTML might want to do it an implementation-independent fashion (rather than relying specifically on, say, React).

To be clear it isn't something I'm in need of anytime soon.

chexxor commented 5 years ago

I attempted to make a DOM typeclass library, unrelated to Concur, but wanted to share my experience. The hardest part was trying to be polymorphic over the data types returned from the DOM methods, because they have sub-typing relationships and some other reason... So, that part of it might be unavoidable to use concrete types.

ajnsit commented 5 years ago

I don't fully understand this. The view part of a widget is swappable, and nothing inside Concur.Core namespace depends on the actual view type. The only real dependencies on the view are the 2-3 el... functions inside Concur.React, but those are only used in the actual DOM element creation which is highly React specific. I don't think we get a lot of mileage out of generalising these.

Basically to port Concur to a new backend, all you would need is rewrite the el... functions, write some smart constructors for the new view type which use those el... functions, and write a rendering/run function to actually render the view type on the backend. It's pretty minimal code.

It's on my TODO list to separate out the generic Concur stuff into a purescript-concur-core package, and have purescript-concur-react depend on it.

I've also been meaning to write a canvas integration as an example of using a different backend. Perhaps I should go ahead and do that once core is separated.

bbarker commented 5 years ago

@ajnsit Good to know about implementing the el functions.

Say I want to write the following function:

    tabPageDiv' :: El'
    tabPageDiv' els =
      div [className "pure-g"] [
        div [menuTypeClasses] [
          div [tabColClasses] els
        ]
      ]
      where
        menuTypeClasses = classList $
          map Just ["pure-menu", "pure-menu-horizontal"]
        tabColClasses = classList $
          map Just ["pure-u-1", "pure-u-md-1-3"]

Since this uses div from the Concur.React module, and say someone else has a Concur.Vue module - it would be good if this code could work with either since the idea is that this function tabPageDiv' would be part of a library, not a user-application. After all, div is standard - maybe how React deals with this is highly specific, but I would think the HTML interface (as supported by Concur) for e.g. div would be fairly standard.

It's on my TODO list to separate out the generic Concur stuff into a purescript-concur-core package, and have purescript-concur-react depend on it.

+1

ajnsit commented 5 years ago

The original plan was to support interop between multiple backends only at a user level, i.e. the Vue backend would define functions like div with the same signature, and then the user just has to change the import from Concur.React to Concur.Vue.

But I see the value in having library code also be reusable in the same way. So a library of widgets would not import any particular backend and could be shared between different backends.

I'll keep this issue open until we have this implemented.

bbarker commented 5 years ago

I just recalled backpacks, which might be useful for this. But I don't think Purescript has them yet: https://github.com/ezyang/ghc-proposals/blob/backpack/proposals/0000-backpack.rst#motivation

ajnsit commented 5 years ago

Started making some progress on this with https://github.com/ajnsit/purescript-concur/commit/0135377fb11dc54d8a8f5cc6e6321a05f6ff7ed3, https://github.com/ajnsit/purescript-concur/commit/11025285ad1ccdf462e43e59951917b61cab0ffa, and https://github.com/ajnsit/purescript-concur/commit/6e16e62e60e86701fcde4b62965b33e6eeec664f

bbarker commented 4 years ago

Just to discuss your original plan:

The original plan was to support interop between multiple backends only at a user level, i.e. the Vue backend would define functions like div with the same signature, and then the user just has to change the import from Concur.React to Concur.Vue.

I've come across other areas in PureScript where I could really benefit from some template-based programming, using something like a pre-processor (though a non-existent PureScript-specific templating system might be preferable, I doubt it will happen anytime soon). Perhaps using something like e.g. heterocephalus or haji, but this would at least be a simple application of it.