purescript-concur / purescript-concur-react

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

Docs added for basic types? #13

Closed bbarker closed 5 years ago

bbarker commented 5 years ago

Hey, sorry if this is an inappropriate place to ask - feel free to close and redirect me (gitter seemed quiet).

I was looking at a very basic example:


rootWidget :: forall a. Widget HTML a
rootWidget = D.text "Hello World"

main :: Effect Unit
main = runWidgetInDom "root" rootWidget

And I was wondering what the two type parameters are to Widget - especially a since it seems obvious HTML is probably a given for most normal work. It looks like a is unused here - could it be unit (())?

I looked at (slightly) more advanced examples and got the impression that a is probably some data that is stored in the widget.

It might be useful to say a few words about the widget such that they show up on pursuit, though I'm new to purescript and not really sure if pursuit is the equivalent in popularity to hackage.

I haven't used Elm, and react only a little a while back - but if should read up on something external to Concur, let me know.

ajnsit commented 5 years ago

Have you looked at the documentation site? - https://github.com/ajnsit/concur-documentation/blob/master/README.md. I think I answer most questions there. If sometime on that page is unclear I would be happy to improve it. I do need to add documentation that show up on pursuit. I'll add it to my todo list.

To answer your question - Widget HTML a represents a widget that has an HTML view and returns a value of type a. In purescript if the type of a is fully polymorphic then it's equivalent to returning Void i.e. the uninhabited type. Which is another way of saying that this widget will never finish.

The advantage of having a fully polymorphic type as the return value of a Widget is that you can drop it in anywhere on the page without changing the rest of the page's logic. This makes intuitive sense as well because changing the location of static widgets (i.e. widgets that never return any data, like say a text heading) shouldn't ever necessitate changing/reorganising the logic of the page.

I hope that answers your question.

bbarker commented 5 years ago

wow, sorry - totally missed that, and no excuse for doing so. The docs look great, going through them now.

Looking forward to trying it out; just read about Widgets and reminded me of something I came up with for widgets in a Scala FRP framework is something like the below:

  sealed abstract class AbstractComponent[D](view: () => Node, model: () => Rx[D])
  final case class Component[D](view: () => Node, model: () => Rx[D])
  extends AbstractComponent[D](view, model)

  object Component {
    def applyLazy[D](view: => Node, model: => Rx[D]): Component[D] = {
      lazy val viewMemo = view
      lazy val modelMemo = model
      Component[D](() => viewMemo, () => modelMemo)
    }
  }

It wasn't great in one sense: the Rx is like an FRP stream. Creating a dynamic collection of such things and managing them always seemed difficult - lots of FRP machinery, not easily composable, sometimes difficult to work at all. The type looks similar to Widget, but mean rather different things.