Coder Social home page Coder Social logo

Comments (14)

paf31 avatar paf31 commented on July 22, 2024

I started by writing "I think you want the Strong instance.", then changed it to "I think you want the Choice instance.", then realised neither does quite what you want, which is surprising to me, because I thought this was simple to do. I think what we need is something like

SF1 a b -> SF1 c d -> SF (Either a c) (Tuple b d)

This would keep the latest state from the side which didn't provide the input. Then you could use Functor to turn Tuple (HTML b) (HTML d) into HTML (Either b d).

from purescript-halogen.

jdegoes avatar jdegoes commented on July 22, 2024

SF1 a b -> SF1 c d -> SF (Either a c) (Tuple b d)

Now why does this look familiar? 😄

It occurs to me in our previous design attempts, we attempted to use prisms / lenses too early. In reality, you have to keep composing using nested eithers and tuples, and only at the end invmap them into sum and product types (well, I suppose you can do it along the way, once you reach a point where there's an isomorphism; the nesting combinators in Either and Tuple should make short work of this).

from purescript-halogen.

natefaubion avatar natefaubion commented on July 22, 2024

This would keep the latest state from the side which didn't provide the input. Then you could use Functor to turn Tuple (HTML b) (HTML d) into HTML (Either b d).

This works, but its really awkward the moment you have to scale it. Say merging 5 different views into one document:

app1 :: PureView Count
app2 :: PureView String

fit :: forall f a b c. (Functor f)
                    => (a -> c)
                    -> (b -> c)
                    -> Tuple (f a) (f b)
                    -> Tuple (f c) (f c)

app3 :: forall p. SF1 (Either
                        Count
                        (Either
                          String
                          (Either
                            Count
                            (Either
                              String
                              Count))))
                      (Tuple
                        (HTML p Count)
                        (Tuple
                          (HTML p String)
                          (Tuple
                            (HTML p Count)
                            (Tuple
                              (HTML p String)
                              (HTML p Count)))))
app3 = app1 `combineLatest` (app2 `combineLatest` (app1 `combineLatest` (app2 `combineLatest` app1)))

Maybe I'm being dense, but the composition of fits to actually put this together in such a way that I could embed these in a document makes my head spin a bit. I can't speak to @jdegoes suggestion as I don't really understand it.

from purescript-halogen.

cryogenian avatar cryogenian commented on July 22, 2024

😄 Indeed, this is very familiar. I believe that component based approach won't work in purescript.
One option is to make input polymorphic and then use sum type constructors over Html i.e.

type Counter o = {count :: Number |o} 
type Message o = {message :: String |o} 

data CounterInput = Inc | Dec 
data MessageInput = Input String  
renderCounter :: forall a o. Counter o -> Html a CounterInput 
renderCounter state = 
  div_ [
    p_ [text (show state.count],
    a [onclick (const $ pure Inc)] [text "inc"],
    a [onclick (const $ pure Dec)] [text "dec"]
  ] 

renderMessage :: forall a o. Message o -> Html a MessageInput 
renderMessage state = 
  div_ [
    p_ [text state.message], 
    form_ [input [onchange (pure <<< Input] []]
  ]

data BothInput = Counter CounterInput | Message MessageInput 

renderBoth :: forall o a. {counter :: Number, message :: String | o} -> Html a BothInput
renderBoth state = 
  div_ [
    Counter <$> renderCounter state,
    Message <$> renderMessage state
  ]

Don't know if it's helpful, though

from purescript-halogen.

natefaubion avatar natefaubion commented on July 22, 2024

Yeah, this is kind of what I wanted to see if I could avoid. Part of the reason is just that then it doesn't seem like there's a need for all the signal function machinery. The machinery seemed to provide a nice way to encapsulate an evolving component, but the ensuing type class tetris feels complicated.

from purescript-halogen.

paf31 avatar paf31 commented on July 22, 2024

I think that lenses and/or prisms could provide a solution. It seems I was wrong about prisms in the past @jdegoes, and that Review is what is needed to turn a prism around:

http://hackage.haskell.org/package/lens-4.8/docs/Control-Lens-Review.html

With this, I think we can use a Prism to adapt a SF i1 (HTML i1) into an SF i2 (HTML i2).

Although, I'm confused. Now I don't understand how a prism composed with a lens can still be a prism.

from purescript-halogen.

natefaubion avatar natefaubion commented on July 22, 2024
renderBoth :: forall o a. {counter :: Number, message :: String | o} -> Html a BothInput
renderBoth state = 
  div_ [
    Counter <$> renderCounter state,
    Message <$> renderMessage state
  ]

In general I like the fmap idiom here rather than manually threading a function composition, but won't this get more and more expensive the more you nest since they don't fuse? If you have say 5 levels, the components at the leaves will get redundantly mapped-over 5 times? I'm talking outside of my comfort-zone here, but could we turn the HTML type into a coyoneda-type-thing and get fusion?

Also outside of my comfort zone, but the other reason this feels me wanting is that its kind of like manually nesting monad transformers without the help of a MonadTrans type class. In somewhat relation to #45, I don't think there is going to be any way to avoid composing UIs since various components may have any one of view/state/controller/handler/renderer. Manually nesting things is fine if you only have to do it once, but if you potentially have to do that multiple times to get effects/placeholders I think it will quickly go beyond mostly-harmless-boilerplate. Is there potentially a MonadTrans sort of UI class we can use to lift all the pieces without as much boilerplate?

from purescript-halogen.

paf31 avatar paf31 commented on July 22, 2024

I've added mergeWith which takes a combining function. This should help a little, but I think that prisms will provide a general solution. It should be simple to layer them on top of the existing code.

from purescript-halogen.

jdegoes avatar jdegoes commented on July 22, 2024

I would also suggest a PR to Data.Tuple.Nested and Data.Either.Nested to add type synonymous such as: Tuple3, Tuple4, Tuple5, etc., and Either3, Either4, Either5, etc. Combine this with some iso goodness so you can translate to / from compositional products / sums to ADT products / sums, and composition using combinators like combineLatest should be pretty easy.

'Excessive typing' pain that is completely type safe and impossible to get wrong is no pain at all. Because you only have to type it once, but you have to maintain the app forever.

from purescript-halogen.

paf31 avatar paf31 commented on July 22, 2024

It's a real shame there isn't X such that X is to Applicative as Comonoidal is to Monoidal, which could give us nice syntax like (<*>) on the left hand side of the function arrow.

from purescript-halogen.

paf31 avatar paf31 commented on July 22, 2024

I've added mergeWith' to make deconstructing inputs a little simpler where needed. Shall I close this then? I think if we're committing to Tuple and Either, then Profunctor should give us all we need to map isos over SF and SF1.

from purescript-halogen.

jdegoes avatar jdegoes commented on July 22, 2024

One option is to make input polymorphic and then use sum type constructors over Html i.e.

I do think that polymorphic sum types, done this way or through prisms (+ maybe type classes), could be quite useful to ease composition.

I think if we're committing to Tuple and Either, then Profunctor should give us all we need to map isos over SF and SF1.

Interested in @natefaubion's feedback here, I think with a few helpers this could definitely work, and could be a useful building block for other approaches, if necessary.

from purescript-halogen.

paf31 avatar paf31 commented on July 22, 2024

I wonder if Either a b ... z ~ forall r. (a -> r) -> (b -> r) -> ... -> (z -> r) -> r can help to make an "Applicative-on-the-left":

lift2 :: forall a b i x. (forall r. (a -> r) -> (b -> r) -> (i -> r)) -> p a x -> p b x -> p i x
lift3 :: forall a b c i x. (forall r. (a -> r) -> (b -> r) -> (c -> r) -> (i -> r)) -> p a x -> p b x -> p c x -> p i x

etc.

Is there a corresponding <*>-like operator?

from purescript-halogen.

natefaubion avatar natefaubion commented on July 22, 2024

I like the Tuple/Either route if we can make it comfortable. Like I said earlier, if we were going to manually compose/wrap/dispatch inline, and only use the Signal machinery at the top level, then I think you could just do away with it all together (or just keep it internal). For now it would be awesome to be able to write a schema once with some combinators that would give me something I could dimap over my composed signal graph and have it just work out (I don't know what that would actually look like). Then in the future if we get some Template PureScript goodness, we could automatically generate it straight from the ADT and get boilerplate-free composition.

from purescript-halogen.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.