Comments (14)
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.
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.
This would keep the latest state from the side which didn't provide the input. Then you could use
Functor
to turnTuple (HTML b) (HTML d)
intoHTML (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 fit
s 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.
😄 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.
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.
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.
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 UI
s 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.
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.
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.
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.
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.
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.
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.
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)
- `tellAll` function is not re-exported in Halogen module
- Enabling `StateT` with `HalogenM` HOT 1
- Export tellAll from Halogen.Query to Halogen HOT 2
- Reading Effects chapter -> Could not match type ResponseFormat String with type AffjaxDriver HOT 4
- Question: how to handle events coming from a js app? HOT 2
- Communication with JS loaded via CDN HOT 2
- Child component gets rendered outside of parent, being moved to bottom of HTML body HOT 6
- `raise` should not be a blocking operation HOT 8
- Discussion: CSS strategy for halogen applications HOT 20
- Question: body-level events HOT 3
- Order of properties matters when using `value` with `min` / `max` for `InputRange` HOT 3
- Change kind of slots to not be `Type`
- `RenderSpec` doc comment still mentions `h` parameter
- Doc: the examples of "An Aff Example: HTTP Requests" give TypesDoNotUnify Error on Halogen v7 HOT 1
- Select Multiple Selected does not work HOT 4
- A bug? Weird behavior of text input fields. HOT 4
- Child component is destroyed while parent component handles output from that child HOT 5
- Array state updates HOT 4
- open and showModal are missing for dialog HOT 6
- The Component type should have role annotations
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from purescript-halogen.