Experimenting with alternative worlds - deferred & prompt signals

94 views
Skip to first unread message

Rehno Lindeque

unread,
Jan 29, 2015, 10:12:27 AM1/29/15
to elm-d...@googlegroups.com
Hi all, this has already been discussed to death but I decided to experiment a bit and see what an alternative world where Signals are divided into prompt signals (initialized with a value) and deferred signal ((un)initialized as an empty signal) would look like. If you're not sure what I'm talking about, see https://github.com/elm-lang/core/issues/148).

This alternative package is over here: http://package.elm-lang.org/packages/rehno-lindeque/elm-signal-alt/lastest. It includes defered versions of the Mouse and Touch modules.

Please note that this is only an experiment, and a really rough one at that - DON'T use it in production! :)

Rehno Lindeque

unread,
Jan 29, 2015, 10:15:50 AM1/29/15
to elm-d...@googlegroups.com

Evan Czaplicki

unread,
Jan 29, 2015, 11:17:42 AM1/29/15
to elm-d...@googlegroups.com
elm-d3 has a concept of Streams, described here which have no default value and otherwise are the same. Not sure if that's what your looking for, but it seems relevant.

--
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.

Rehno Lindeque

unread,
Jan 29, 2015, 1:50:24 PM1/29/15
to elm-d...@googlegroups.com
elm-d3 has a concept of Streams, described here which have no default value and otherwise are the same. Not sure if that's what your looking for, but it seems relevant.

Thank you, that's useful to look at. Mostly I think I wanted to clarify for myself the semantics that signals have. I haven't really had the opportunity to work hands-on with signals like Mouse.clicks, instead all of the signals I've worked with so far has been "prompt". So this was an exercise in clarifying semantics for myself, my understanding is something like this...

// Test.js
widget = elm.embed(Test,
  { input: 1
  , list: [1,2,3,4,5]
  });
widget.ports.input.send(2);
widget.ports.input.send(3);
widget.ports.input.send(4);
widget.ports.input.send(5);

-- Test.elm
port input : Signal Int
port list : List Int

sig   : Signal Int
sig = input

psig : Prompt.Signal Int
psig = input

dsig : Deferred.Signal Int
dsig = defer input

{- Semantics:

    sig  == (1, <2,3,4,5>)     : (a, <a>)
    psig == <1,2,3,4,5>        : <a>
    dsig == <2,3,4,5>          : Deferred <a>
    list == [1,2,3,4,5]        : List a
    
    foldp (\x r -> r ++ toString x) "" sig  == ("", <"23", "234", "2345">)
    foldl (\x r -> r ++ toString x) "" psig == <"1", "12", "123", "1234", "12345">
    foldl (\x r -> r ++ toString x) "" dsig == <"2", "23", "234", "2345">
    foldl (\x r -> r ++ toString x) "" list == ["1", "12", "123", "1234", "12345"]

-}

Jeff Smits

unread,
Jan 30, 2015, 3:38:25 AM1/30/15
to elm-discuss
I don't think there is such a conceptual difference between sig and psig. It's just that foldp is weird. 

Rehno Lindeque

unread,
Jan 30, 2015, 5:06:30 AM1/30/15
to elm-d...@googlegroups.com
I don't think there is such a conceptual difference between sig and psig. It's just that foldp is weird. 

Yes - I actually secretly hoped this would nudge Elm folk to see psig as the 99% use case and dsig as the exception that requires special treatment :). It's only a gentle nudge though, I suspect the argument's been settled for a while - I don't want to beat a dead horse.

Jeff Smits

unread,
Jan 30, 2015, 7:43:29 AM1/30/15
to elm-discuss

I don't want to encourage violence towards deceased equines, but I'd like the discussion around the behaviour of foldp to be rekindled.
In my memory it hasn't been discussed to death at all. There used to be a foldp' like is now in my package in core, back in Elm 0.7 or something. When that function suddenly got removed, there was a discussion about the usefulness of the function. That's the first time I saw a proposal of a function like the one you now call foldl. But AFAIK that was the only serious discussion about it and didn't actually result in any action being taken.

My take on this is that changing the behaviour of foldp is a breaking change and those are best done ASAP. And I'd like foldp to change in behaviour so it doesn't ignore the initial value of the input. I don't think it will be problematic for most use cases and the ignoring of initial input is a stumbling block for beginners. Evidence that it's confusing for beginners can be found on the mailing list (and on IRC, if there were logs).

John Mayer

unread,
Jan 30, 2015, 8:58:01 AM1/30/15
to elm-d...@googlegroups.com

Just add the other foldp to signals extra. No big deal.

--

Rehno Lindeque

unread,
Jan 30, 2015, 10:04:40 AM1/30/15
to elm-d...@googlegroups.com, john.p....@gmail.com

Just add the other foldp to signals extra. No big deal.

One thing that does worry me is that it feels as though (I have no evidence for this) getting the foldl behavior back from foldp looks sort of expensive... I was tempted to just use that by default, but there's a big disadvantage that goes with fighting the defaults. I'd rather go with the consensus, even if it ends up being something I take issue with.

I want to make clear, I don't feel this is necessarily a problem of not being able to express something. I just feel that mentally distinguishing between foldp and foldl is a stumbling block that every newcomers gets to stub their toe on at least once. By contrast, explicitly unboxing a deferred signal does not seem horrible to me, except that it would be nice to have a largely shared API which seems unwieldy in the absence of typeclasses. Also, admittedly, deferred signals seem like they're going to be all over the place with promises, so my suggestion that they're going to be rare is probably a bad one in retrospect.

I think the main argument in many of these Elm posts is whether it's "ok" to push some of the complexity out to types, leading to some implicitness at the value level. I don't mind this too much myself, especially if I feel it's telling me something important - but this is up to Evan to say since he's trying to win over the dynamically typed crowd (which I think is fantastic; client-side gui really benefits from having a large ecosystem).

Rehno Lindeque

unread,
Jan 30, 2015, 10:46:10 AM1/30/15
to elm-d...@googlegroups.com, john.p....@gmail.com
Ok, sorry for the noise. I do actually think that perhaps the "right" solution in mind would be...

Mouse.clicks : Signal (Maybe ())

...instead of..

Mouse.clicks : Signal ()

...and, similarly, looking at the old Http...

type Response a = Success a
                | Waiting
                | Failure Int String
                | Unsent              <-- with an added initial state

...and then simply making all signals prompt with conventional foldl behavior. My suspicion is that there is almost always special-case behavior for the first value in any real world "defered signal" and that cases like...

foldp (\c -> c + 1) Mouse.clicks 

...are actually the exception. In other words I'm 100% ok with occasionally (and probably rarely unnecessarily) paying this cost...

foldl (\mc -> withDefault 0 mc + 1) Mouse.clicks

...and so my argument is going to be square on the side of a foldl over foldp. In fact I wonder if there might be some nicety like this that would make it all go away:

withInit 0 (foldl (\c -> c + 1)) Mouse.clicks

 

Rehno Lindeque

unread,
Jan 30, 2015, 11:39:54 AM1/30/15
to elm-d...@googlegroups.com, john.p....@gmail.com
Ugh, sorry again..

foldl (\_ mc -> Maybe.withDefault -1 mc + 1) 0 Mouse.clicks

maybe with a helper

accum : (a -> a) -> a -> Signal (Maybe ())  -> Signal a
accum (\c -> c + 1) 0 Mouse.clicks

or something like that
Reply all
Reply to author
Forward
0 new messages