--
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.
[...] this API might not let me do anything I couldn't do before, but it might let me do it in a nicer way.
I suspect the best use of this decentralized state will be in refactoring
I guess what I'm trying to say is, used poorly signal loops can make for worse code, and used well they can make for better code.
If I use old on a signal more than once, is only one copy retained?
If I use old on a signal more than once, is only one copy retained?I don't understand this question. Can you rephrase it? Or give an example?
Agree with this. Rather than add the keyword, let's fix recursive signals now (with an appropriate error) and then introduce old (or some other name) as a function that allows an escape hatch.
Personally I favor the introduction of GADT style annotations: using natural numbers for topological depth to prevent recursive loops, and a boolean is-from-a-loop tags on looped signals to enforce the use of sampleOn to prevent infinite change-event churning. I know that this adds significant cognitive overhead, so maybe a different implementation is more appropriate, but those are the two invariants that I believe we ought to plug.
Yes I have also preferred that one Dobes. The implementation is by and large the same stuff but I much prefer this API. You don't have to worry about the recursive signal problem since you've inverted the API; though you still get the infinite hamster wheel of change events. But it's not a new idea.
Evan, what are the things you must see to start to consider adding this?
What happens when you have:
f = merge (constant 0)
Is the output value always change or nochange? I would argue the latter; this would happen anytime the output signal is an unsampled descendent of the top of the loop.
Are we even interested in forbidding this behavior? It's a problem with every loop proposal thus far that doesn't enhance the signal type.
Er, sorry, in the previous email I meant former, that it would necessarily be always a change event. And I think that's fine and that simply documenting works. I think this applies to both Jeff's and Dobes's API.
Personally I like lumping all the input and state into one big pure automaton, so you lost me at the "why" part
If I write my components as a pure library I can fire it up and pass in whatever I want, use it in unit tests with "fake" inputs, use it multiple times or just once, stuff like that. The pure language is more re-usable than the signal language.
Perhaps because the language is pure, `lift` could use the same mechanism used by "dropRepeats" to cache the previous result, since the lifted function is guaranteed to produce the same output given the same input (I think?). Since there are relatively few types of signals that are stateful (foldp, automaton) signals could have a special update type that indicates that the signal was "touched" but the output was a repeat. Stateless signals can propagate this if all their inputs are also only touched, much like how they propagate the "no change" events now. I think this may not affect the semantics but would improve performance.
let's fix recursive signals now (with an appropriate error) [...]
[...] and then introduce old (or some other name) as a function that allows an escape hatch.
Personally I favor the introduction of GADT style annotations: using natural numbers for topological depth to prevent recursive loops, and a boolean is-from-a-loop tags on looped signals to enforce the use of sampleOn to prevent infinite change-event churning. I know that this adds significant cognitive overhead, so maybe a different implementation is more appropriate, but those are the two invariants that I believe we ought to plug.
Evan, what are the things you must see to start to consider adding this?
Signal.loop : (Signal b -> Signal b) -> b -> Signal bWhile think about the formal write-up, I considered using this at the most basic primitive. I called it fix because it's a Signal fixpoint computation, but it's otherwise the same. It's also very similar to loop from ArrowLoop. I already have a full translation to CML in the same style as Evan uses in his thesis, but then I figured there is something that's not so nice about this primitive. Like Arrows and foldp, this fixpoint for Signals will still need to use tuples to express a situation like this:
Yes I have also preferred that one Dobes. The implementation is by and large the same stuff but I much prefer this API. You don't have to worry about the recursive signal problem since you've inverted the API
I think it should use the same rules as foldp; that is, if foldp doesn't have a hamster wheel problem then neither should this approach.
Are we even interested in forbidding this behavior? It's a problem with every loop proposal thus far that doesn't enhance the signal type.
So let me put on my user hat:
I do want to see this and there is definitely a use case for signal loops instead of just foldp loops. The pause fps example is a good one.
I don't like the keyword and would prefer a function: you mention nesting... what's actually wrong with nesting? Maybe nesting is what I need for my use case... can you explain why you think nesting should be forbidden? How does the keyword forbid nesting?
As a (power) user, I also don't care a ton about the invariants: let me worry about hamster wheel safety and recursive signal definitions. (Here I have changed my mind. I'm skeptical that we should add this sort of static analysis to the compiler anyway: unlike the original CFRP paper, there's nothing special about the signal type or the signal combinators in the Elm implementation.)
So as I put my implementer hat back on, as far as the API, I'm leaning towards the simplest, but with the behavior you describe.
Signal.loop : a -> Signal a -> Signal a
I think we're making progress, but we should hop on a hangout. The main problem as I see it is that the compiler doesn't know much about the signal graph structure. I'd want to double back to the thesis for guidance on whether we can start to design improvements that make signal graph structure static analysis possible.