I like Signal + Events better. I'd argue to keep them both in the standard library. I often think that Event a = Signal (Maybe a). Previously, when dealing with user input in Elm, I'd unavoidably encounter Signals that start with a Nothing and then afterwards always be Just something. I think this will be only more common with the new release and how it handles inputs and outputs with Tasks/Promises. So, I lean towards making Event a first class pattern and keeping the standard library combinators following this pattern to force good architecture.
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
import Core
mySignal : Core.Signal a
myEvents : Core.Events b
empty : Feed a
--
Let's try to organize all the different things people are saying:Signal:
- Pro: Keep existing terminology, minor changes needed in 0.15 with the ability to easily move towards having a Signal and Events library. Very easy to present this concept.
- Con: a lot of the typical functions are nicer to use when you make a distinction.
From now on, all the versions have the con that "presenting becomes a two part process" which maybe will be confusing.Events + Signal:
- Pro: Keeps existing terminology as much as possible.
- Con: It's weird to say "Events" when "Stream" is a commonly used term that works well. People don't know what a Signal is.
--
I think stream should be reserved for lazy lists. Other wise it's too far off from standard FP terminology.
Signal:
- Pro: Keep existing terminology, minor changes needed in 0.15 with the ability to easily move towards having a Signal and Events library. Very easy to present this concept.
From now on, all the versions have the con that "presenting becomes a two part process" which maybe will be confusing.
- Con: a lot of the typical functions are nicer to use when you make a distinction.
TL;DR: Varying without an implicit dropRepeats may be contraintuitive.
Some musings about
having only one type Signal
, vs.
two, Stream
and Varying
(or
whatever they are termed): How would a newcomer to Elm think
about these concepts?
When I was a newcomer I needed some time to realize that a signal has these two aspects: being a time-varying value and having some “pulse”, which potential updates even if the value doesn’t change. Like a unified representation of state and events.
I have read a post from Evan stating that modern research in FRP prefers the unified concept of signals over the distinction of state and events. Ok I thought, nice, a nifty choice to keep the language lean.
Then there is this problem with obligatory start values for signals. IIRC this was the initial motivation for the split into Stream and Varying. A Stream is a Signal without a start value, and a Varying is a Signal with a start value.
But does this operational model really meet the mental model of state and events? No, at least not in one specific point: As proposed a Varying can still update even if the value stays the same (not varying, so to say), and it tell its child-nodes about this non-change. This seems contraintuitive and hard to explain.
We could come around
with implicit dropRepeats
in
those API functions that return a Varying result, e.g. map
, toVarying
, etc.
Is this feasible? Would there be any serious consequences in
efficiency or semantics?
Honestly, I’m feeling a bit confused about the best way through operational and intuitive models and their trade-offs. I hope my writing makes some sense anyway.
Personally I'd rather have a signal of maybe for events, rather than two concepts. It wouldn't be hard to have a separate set of signal functions that map over the maybe for you, but you still have the option to work with the maybe directly as well.
Events can actually be defined as nothing except in the update on which the event occurred. But there might be other signals that come and go as well; a modal application might turn off a subset of signals to nothing when they don't apply. Like if you are on the game menu the in-game related signals can flat line.
Excuse me if I am missing something fundamental but could we define Signal
in terms of Stream
like so?
type Stream a = Stream a
type Event a = Changed a | Unchanged a
type Signal = Stream (Event a)
Stream
, Event
and hence Signal
would all be “applicative”. An alternative to Event
could be Sample
though I think I like that name because I have done some signal processing. I wrote a similar abstraction for Helm: Signal and Sample.
Signal should have been a type alias
for valid Elm code or:
type Signal = Signal (Stream (Event a))
… and I keep forgetting the type variable. For clarity:
type Stream a = Stream a
type Event a = Changed a | Unchanged a
type alias Signal a = Stream (Event a)
-- or
type Signal a = Signal (Stream (Event a))
Yes, that is a more general explanation but let’s talk about what to expose to the user.
The user doesn’t care about the initial Missing/Create/Delete values. Similarily the value “Diffed” against doesn’t matter.
This simplified Update
/Event
/Sample
type I had is actually useful in illustrating the difference betweens Streams and Varying/Signal (I’ll just stick to using Varying henceforth).
Like Thomas said:
When I was a newcomer I needed some time to realize that a signal has these two aspects: being a time-varying value and having some “pulse”, which potential updates even if the value doesn’t change.
So I would propose something like this API:
type Update a = Changed a | Unchanged a
valueOf : Update a -> a
valueOf update = case update of
Changed x -> x
Unchanged x -> x
type alias Varying a = Stream (Update a)
-- instead of destructure
streamValues : Varying a -> Stream a
streamValues = Stream.map valueOf
-- a more general fold
fold : (a -> b -> b) -> b -> Stream a -> Stream b
-- instead of subscribe
dropRepeats : Stream a -> a -> Varying a
dropRepeats stream initial =
fold
(\x z -> if x == (valueOf z) then Unchanged (valueOf z) else Changed x)
(Unchanged initial)
stream
This way you can write functions lifted to Stream
and convert them to Varying
if you have something sensible to do with the Update
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.
What do you mean by "higher arity maps are possible"?
A big difference between lists and Timelines is push versus pull. We
can have an infinite list and evaluate it whenever needed using lazy
evaluation. With a timeline this doesn't work since its tail is in the
future. Instead we react to new items as they arrive.
(I probably should have read more about the theory of FRP before
getting into this.)
But I don't think there's anything wrong with having
an "end of Timeline" marker so that you know that no more data is
coming, and the subscriptions to the Timeline can be collected.
Really, all you have is the present.
On 23 March 2015 at 12:24, Jeff Smits <jeff....@gmail.com> wrote:
In representation of a Signal might considered be a special case Stream that has an initial value at program start, but the semantics of a Signal are quite different. It's not (just*) a stream of events, it's a value that changes over time in a discrete manner, therefore there is always a value, therefore higher arity maps are possible. This is not the case for a normal Stream and makes it worthwhile to distinguish between them in the type system IMO.* The Signal we're familiar with keeps the event information of it's value changes, so it's both an event stream and a value varying over time. I suspect that's the idea of Stream/Varying, Stream is just the events, Varying is just the value over time where you cannot have an observable event as long as the value doesn't change, whereas with Signal you can.
Ah thanks, with this explanation and Evan’s new diagrams posted in another thread I can see where my thinking was wrong in a way. My Stream
type was more of base of Signal/Varying that didn’t know anything about changes, just a constantly updating sample so to speak.
So what about going the other way and actually encoding type alias Stream a = Varying (Maybe a)
. Would it be useful?
Re: Timeline, I don’t like it because it suggests a fixed number of events somehow. But I am totally over the naming discussion anyway. Call it whatever you like, I can adapt. :)
--
On 24 March 2015 at 07:11, Jeff Smits <jeff....@gmail.com> wrote:
This is my interpretation, it's never been clearly defined to be so. But it's the only way I can imagine that Varying differs from Signal. But the current implementation of varyingToStream seems to indicate Varying is just a plain old Signal.If this is really supposed to be the case, then yestype alias Stream a = Signal (Maybe a)can work as the signal will be Nothing until the first event from the stream and then have updates of Just (value of the stream event).
I think this is where the implementation differs from the concept in a way and may be what had led me on the wrong path as well. I think the value of Stream is conceptually Nothing after it has passed through the graph until it receives another value. The implementation holds on to the value as it is likely read several times while being processed and there is no point in discarding it (because it cannot be read after that). It is quite confusing I must say. Please do correct me if I am wrong about any of this.
On 24 March 2015 at 17:03, Evan Czaplicki <eva...@gmail.com> wrote:
Jeff, you are correct that (Signal a == Varying a) and that (Signal (Maybe a) == Stream a) where it starts Nothing and then is Just on every update.
Either way, what do you think about defining it as (Varying (Maybe a)) on the type level in Elm? Wouldn’t it make the from/to conversions clearer? I kind of like it as an explanation but I have no idea if it’s useful in practice and have yet to use Stream/Varying in anger.
--
I think although conceptually they are distinct, I thought the merging of the two bought something. Or at least I thought so, I'm a bit fuzzy on exactly what.
There's real value in having separate concepts. Varying and Stream play distinct roles, despite their technical similarity.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
--
You received this message because you are subscribed to the Google Groups "Elm Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.