Yeah looking
at https://github.com/elm-lang/core/blob/4.0.4/src/Native/Platform.js shows
that it would be very easy to add that functionality to core.
On Monday, August 8, 2016 at 8:48:26 AM UTC-6, OvermindDL1 wrote:
>
> I do say that I wish there were some way to make some 'update' call as
> no-view and/or no-subscription re-call needed. Like instead of returning
> `( model, Cmd.none )` we could do `( model, Cmd.cancelView )` or `( model,
> Cmd.cancelSubscription )` or both via `Cmd.batch`, or perhaps as a
> three-argument tuple that defaults to `( model, Cmd.none, StateChanges.none
> )` or so, which would default to calling everything. I have a lot of
> update messages that are handled that do not change the view and/or
> subscriptions and it would be nice to prevent calling those somehow. Hmm,
> actually a backward compatible change would be to add a new Program
> callback, in addition to the usual `init`, `update`, `subscriptions`, and
> `view`, add another one that I will call just `blah` for now, optional in
> the Program or so, but have it be like:
> ```
> blah : Msg -> ( Msg, States )
> blah msg ->
> case msg of
> MyMessageThree _ -> ( msg, States.batch [ States.cancelView,
> States.cancelSubscriptions )
> MyMessageNine arg0 _ -> ( MyMessageThree arg0, States.noChanges ) --
> or `States.none`?
> MyRedrawMessage -> ( msg, States.cancelView )
> MyMessageTwelve _ -> ( msg, States.onlyUpdate )
> _ -> ( msg, States.noChanges )
> ```
>
> And it would be called after `init` and before every call of `update`. It
> would allow an easy way to translate one message type into another (maybe
> even a way to decorate it more so it can get passed to another modules
> update/subscription, this would be a **great** hooking location for
> modules), as well as a way to specify what states should be updated for a
> given message, a default no-op function could be supplied via
> `States.defaultHandle` or so that you could pass to the program so people
> do not have to override it in the easy cases.
>
> Hmm, an idea for a module handler, one of the states could be something
> like:
> ```elm
> MaterialMessage msg -> ( msg, States.delegate {
> update=Material.update, subscriptions=Material.subscriptions } )
> ```
> Which of course the other module could simplify via a helper to:
> ```elm
> MaterialMessage msg -> Material.blah msg
> ```
>
>
> On Monday, August 8, 2016 at 6:49:22 AM UTC-6, Janis Voigtländer wrote:
>>
>> A while back there was a thread
>> <https://groups.google.com/d/msg/elm-discuss/u-6aCwaJezo/fu-HMPy6CQAJ>
>> about filtering subscriptions. The following is related, but can also (and
>> probably better) be consumed and discussed independently. For those that do
>> have that older thread as context in mind, the following differs in two
>> essential ways:
>>
>> - Earlier, the discussion was about generic filtering of arbitrary
>> subscriptions. The following involves no genericity whatsoever. It is
>> only
>> a proposal about the Keyboard API specifically.
>> - The earlier thread was not rooted in practice, since very little
>> stuff had been built yet with subscriptions. In the following, I point to
>> how things have played out in practice, based on uses students have made
>> of
>> the current API in projects.
>>
>> ------------------------------
>>
>> So, on to the subject matter:
>>
>> The keyboard package
>> <http://package.elm-lang.org/packages/elm-lang/keyboard> currently
>> contains functions such as:
>>
>> Keyboard.downs : (KeyCode -> msg) -> Sub msg
>>
>> Common uses (I’ll point to several repositories below) are such that only
>> some keys are relevant for an application. My proposal is to have functions
>> such as:
>>
>> Keyboard.downsSelectively : (KeyCode -> Maybe msg) -> Sub msg
>>
>> where the semantics is that if a given KeyCode is mapped to Nothing by
>> the tagger, then no message gets sent along the subscription; otherwise the
>> Just is peeled off and the message gets sent.
>> ------------------------------
>>
>> Let’s look at a practical case, https://github.com/arpad-m/dontfall.
>> It’s a game, where the player uses the keyboard for part of the control.
>> Important excerpts from the code are:
>>
>> The message type (in
>> https://github.com/arpad-m/dontfall/blob/master/src/BaseStuff.elm):
>>
>> type GameMsg = NothingHappened | ... several other messages ...
>>
>> The subscriptions definition (in
>> https://github.com/arpad-m/dontfall/blob/master/src/main.elm):
>>
>> subscriptions : GameData -> Sub GameMsgsubscriptions d =
>> Sub.batch
>> ([ Keyboard.downs (\c -> if Char.fromCode c == 'P' then PauseToogle
>> else NothingHappened) ] ++
>> if d.state == Running then
>> [ AnimationFrame.diffs Tick
>> , Keyboard.downs (\c -> if Char.fromCode c == ' ' then
>> JumpDown else NothingHappened)
>> , Keyboard.ups (\c -> if Char.fromCode c == ' ' then JumpUp
>> else NothingHappened)
>> ]
>> else
>> [])
>>
>> The main case distinction in the main update function (in
>> https://github.com/arpad-m/dontfall/blob/master/src/main.elm):
>>
>> updateScene : GameMsg -> GameData -> (GameData, Cmd GameMsg)updateScene msg
>> d =
>> (case d.state of
>> ...
>> Running -> case msg of
>> MouseMove (x,_) -> { d | characterPosX = min x d.flWidth}
>> Tick t -> stepTime d t
>> PauseToogle -> { d | state = Paused }
>> JumpDown -> { d | jumpPressed = True }
>> JumpUp -> { d | jumpPressed = False }
>> _ -> d
>> , Cmd.none
>> )
>>
>> Given availability of the functions I propose above, the code could
>> instead look as follows:
>>
>> type GameMsg = ... only the other messages, no NothingHappened ...
>> subscriptions : GameData -> Sub GameMsgsubscriptions d =
>> Sub.batch
>> ([ Keyboard.downsSelectively (\c -> if Char.fromCode c == 'P' then
>> Just PauseToogle else Nothing) ] ++
>> if d.state == Running then
>> [ AnimationFrame.diffs Tick
>> , Keyboard.downsSelectively (\c -> if Char.fromCode c == ' '
>> then Just JumpDown else Nothing)
>> , Keyboard.upsSelectively (\c -> if Char.fromCode c == ' '
>> then Just JumpUp else Nothing)
>> ]
>> else
>> [])
>> updateScene : GameMsg -> GameData -> (GameData, Cmd GameMsg)updateScene msg
>> d =
>> (case d.state of
>> ...
>> Running -> case msg of
>> MouseMove (x,_) -> { d | characterPosX = min x d.flWidth}
>> Tick t -> stepTime d t
>> PauseToogle -> { d | state = Paused }
>> JumpDown -> { d | jumpPressed = True }
>> JumpUp -> { d | jumpPressed = False }
>> , Cmd.none
>> )
>>
>> Advantages:
>>
>> 1.
>>
>> simpler message type, no special role no-op constructor needed
>> 2.
>>
>> no spurious update and render cycles while the game is running
>> 3.
>>
>> less room for bugs in the update logic
>>
>> Some additional comments on the latter two of these points:
>>
>> Re 2., given the current implementation, whenever a key is hit that is
>> not relevant, the update function is still called and produces an unchanged
>> model, which is then rendered, which is extra/useless work. Since the game
>> uses Graphics.*, no use can be made of Html.Lazy.* to avoid the
>> re-rendering. Even if something like Graphics.Lazy.* were available,
>> having to use it would not be as nice/pure as not causing those spurious
>> updates in the first place.
>>
>> Re 3., given the current implementation, there is both more room for bugs
>> in the now and in a potential later, when extending the game. In the now,
>> the programmer has to make sure that NothingHappened does indeed not
>> change the model. Concerning later, imagine that the programmer extends the
>> message type for some reason. With the current version of updateScene,
>> the programmer might forget to actually add a branch for handling the new
>> message, and the compiler would not catch that, because of the _ -> d
>> branch that will silently catch not only NothingHappened but also the
>> new message which was actually supposed to make something happen. With the
>> version of updateScene after the proposed change, the situation would be
>> different. Since there is no _ -> d branch in that Running -> case msg
>> of ... part anymore (thanks to NothingHappened not being a thing), the
>> compiler will immediately complain if the message type is extended but the
>> new message is not handled there. Bug prevented.
>> ------------------------------
>>
>> It’s not only this single project. I have observed students applying
>> different strategies to deal with “Not all keys are relevant to my
>> program”. In each case, using an API with functions of type (KeyCode ->
>> Maybe msg) -> Sub msg instead of (KeyCode -> msg) -> Sub msg would have
>> been conceptually nicer and would have simplified things.
>>
>> Some more example repos:
>>
>> - https://github.com/chemmi/elm-rocket, uses type Key = Left | Right
>> | ... | NotBound and keyBinding : KeyCode -> Key and then needs to
>> make sure to correctly (non)-deal with NotBound in functions like
>> updateKeyDown; whereas just not having NotBound, but having keyBinding
>> : KeyCode -> Maybe Key and using that in a call to a (KeyCode ->
>> Maybe msg) -> Sub msg function would simplify things with the same
>> benefits as in the above more fully elaborated example case.
>> - https://github.com/Dinendal92/Abschlussprojekt-DP2016, less
>> complete project, but with same approach and issues as in the preceding
>> example, using type Key = Space | Unknown and fromCode : Int -> Key.
>> Here, since eliminating Unknown would turn Key into a type with only
>> one constructor, even more conceptual simplifications would be enabled
>> after a switch to the (KeyCode -> Maybe msg) -> Sub msg approach.
>> - https://github.com/Shaomada/Elm-Project, quite elaborate project,
>> structured according to TEA, uses no special Key type, instead maps
>> with Char.fromCode in the calls to the keyboard subscriptions, then
>> has to case dispatch on actual Chars at several places distributed
>> over the update functions of the TEA subcomponents. Subscribing with
>> (KeyCode
>> -> Maybe msg) -> Sub msg functions should allow to eliminate branches
>> at some of those places, removing redundancies and room for bugs.
>> - https://github.com/Sulring/elmaction, similar story (without TEA)
>>
>> <div
>> title="MDH:PGRpdj48ZGl2PjxkaXY+PGRpdj48ZGl2PkEgd2hpbGUgYmFjayB0aGVyZSB3YXMgYSBbdGhyZWFk
>>
>> XShodHRwczovL2dyb3Vwcy5nb29nbGUuY29tL2QvbXNnL2VsbS1kaXNjdXNzL3UtNmFDd2FKZXpv
>> L2Z1LUhNUHk2Q1FBSikgYWJvdXQgZmlsdGVyaW5nIHN1YnNjcmlwdGlvbnMuIFRoZSBmb2xsb3dp
>> bmcgaXMgcmVsYXRlZCwgYnV0IGNhbiBhbHNvIChhbmQgcHJvYmFibHkgYmV0dGVyKSBiZSBjb25z
>> dW1lZCBhbmQgZGlzY3Vzc2VkIGluZGVwZW5kZW50bHkuIEZvciB0aG9zZSB0aGF0IGRvIGhhdmUg
>> dGhhdCBvbGRlciB0aHJlYWQgYXMgY29udGV4dCBpbiBtaW5kLCB0aGUgZm9sbG93aW5nIGRpZmZl
>> cnMgaW4gdHdvIGVzc2VudGlhbCB3YXlzOjxicj48YnI+PC9kaXY+KiBFYXJsaWVyLCB0aGUgZGlz
>> Y3Vzc2lvbiB3YXMgYWJvdXQgZ2VuZXJpYyBmaWx0ZXJpbmcgb2YgYXJiaXRyYXJ5IHN1YnNjcmlw
>> dGlvbnMuIFRoZSBmb2xsb3dpbmcgaW52b2x2ZXMgbm8gZ2VuZXJpY2l0eSB3aGF0c29ldmVyLiBJ
>> dCBpcyBvbmx5IGEgcHJvcG9zYWwgYWJvdXQgdGhlIEtleWJvYXJkIEFQSSBzcGVjaWZpY2FsbHku
>> PGJyPjwvZGl2PiogVGhlIGVhcmxpZXIgdGhyZWFkIHdhcyBub3Qgcm9vdGVkIGluIHByYWN0aWNl
>> LCBzaW5jZSB2ZXJ5IGxpdHRsZSBzdHVmZiBoYWQgYmVlbiBidWlsdCB5ZXQgd2l0aCBzdWJzY3Jp
>> cHRpb25zLiBJbiB0aGUgZm9sbG93aW5nLCBJIHBvaW50IHRvIGhvdyB0aGluZ3MgaGF2ZSBwbGF5
>> ZWQgb3V0IGluIHByYWN0aWNlLCBiYXNlZCBvbiB1c2VzIHN0dWRlbnRzIGhhdmUgbWFkZSBvZiB0
>> aGUgY3VycmVudCBBUEkgaW4gcHJvamVjdHMuPGJyPjxicj4tLS0tLS0tLS0tLTxicj48YnI+PC9k
>> aXY+U28sIG9uIHRvIHRoZSBzdWJqZWN0IG1hdHRlcjo8YnI+PGJyPjwvZGl2PlRoZSBba2V5Ym9h
>> cmQgcGFja2FnZV0oaHR0cDovL3BhY2thZ2UuZWxtLWxhbmcub3JnL3BhY2thZ2VzL2VsbS1sYW5n
>> L2tleWJvYXJkKSBjdXJyZW50bHkgY29udGFpbnMgZnVuY3Rpb25zIHN1Y2ggYXM6PGJyPjwvZGl2
>> PmBgYGhhc2tlbGw8YnI+S2V5Ym9hcmQuZG93bnMgOiAoS2V5Q29kZSAtJmd0OyBtc2cpIC0mZ3Q7
>> IFN1YiBtc2c8YnI+PGRpdj5gYGA8YnI+PC9kaXY+PGRpdj5Db21tb24gdXNlcyAoSSdsbCBwb2lu
>> dCB0byBzZXZlcmFsIHJlcG9zaXRvcmllcyBiZWxvdykgYXJlIHN1Y2ggdGhhdCBvbmx5IHNvbWUg
>> a2V5cyBhcmUgcmVsZXZhbnQgZm9yIGFuIGFwcGxpY2F0aW9uLiBNeSBwcm9wb3NhbCBpcyB0byBo
>> YXZlIGZ1bmN0aW9ucyBzdWNoIGFzOjxicj48L2Rpdj48ZGl2PmBgYGhhc2tlbGw8YnI+S2V5Ym9h
>> cmQuZG93bnNTZWxlY3RpdmVseSA6IChLZXlDb2RlIC0mZ3Q7IE1heWJlIG1zZykgLSZndDsgU3Vi
>> IG1zZzxicj5gYGA8YnI+PC9kaXY+PGRpdj53aGVyZSB0aGUgc2VtYW50aWNzIGlzIHRoYXQgaWYg
>> YSBnaXZlbiBgS2V5Q29kZWAgaXMgbWFwcGVkIHRvIGBOb3RoaW5nYCBieSB0aGUgdGFnZ2VyLCB0
>> aGVuIG5vIG1lc3NhZ2UgZ2V0cyBzZW50IGFsb25nIHRoZSBzdWJzY3JpcHRpb247IG90aGVyd2lz
>> ZSB0aGUgYEp1c3RgIGlzIHBlZWxlZCBvZmYgYW5kIHRoZSBtZXNzYWdlIGdldHMgc2VudC48YnI+
>> PGJyPi0tLS0tLS0tLS0tPGJyPjxicj48L2Rpdj48ZGl2PkxldCdzIGxvb2sgYXQgYSBwcmFjdGlj
>> YWwgY2FzZSwgaHR0cHM6Ly9naXRodWIuY29tL2FycGFkLW0vZG9udGZhbGwuIEl0J3MgYSBnYW1l
>> LCB3aGVyZSB0aGUgcGxheWVyIHVzZXMgdGhlIGtleWJvYXJkIGZvciBwYXJ0IG9mIHRoZSBjb250
>> cm9sLiBJbXBvcnRhbnQgZXhjZXJwdHMgZnJvbSB0aGUgY29kZSBhcmU6PGJyPjxicj48L2Rpdj48
>> ZGl2PlRoZSBtZXNzYWdlIHR5cGUgKGluIGh0dHBzOi8vZ2l0aHViLmNvbS9hcnBhZC1tL2RvbnRm
>> YWxsL2Jsb2IvbWFzdGVyL3NyYy9CYXNlU3R1ZmYuZWxtKTo8YnI+PC9kaXY+PGRpdj5gYGBoYXNr
>> ZWxsPGJyPjwvZGl2PjxkaXY+dHlwZSA8c3BhbiBjbGFzcz0iIj5HYW1lTXNnPC9zcGFuPiA8c3Bh
>> biBjbGFzcz0iIj49PC9zcGFuPiA8c3BhbiBjbGFzcz0iIj5Ob3RoaW5nSGFwcGVuZWQgfCAuLi4g
>> c2V2ZXJhbCBvdGhlciBtZXNzYWdlcyAuLi48YnI+PC9zcGFuPjwvZGl2PjxkaXY+YGBgPGJyPjwv
>> ZGl2PjxkaXY+VGhlIHN1YnNjcmlwdGlvbnMgZGVmaW5pdGlvbiAoaW4gaHR0cHM6Ly9naXRodWIu
>> Y29tL2FycGFkLW0vZG9udGZhbGwvYmxvYi9tYXN0ZXIvc3JjL21haW4uZWxtKTo8YnI+PC9kaXY+
>> PGRpdj5gYGBoYXNrZWxsPGJyPnN1YnNjcmlwdGlvbnMgOiBHYW1lRGF0YSAtJmd0OyBTdWIgR2Ft
>> ZU1zZzxicj5zdWJzY3JpcHRpb25zIGQgPTxicj4mbmJzcDsmbmJzcDsmbmJzcDsgU3ViLmJhdGNo
>> PGJyPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyAoWyBLZXlib2Fy
>> ZC5kb3ducyAoXGMgLSZndDsgaWYgQ2hhci5mcm9tQ29kZSBjID09ICdQJyB0aGVuIFBhdXNlVG9v
>> Z2xlIGVsc2UgTm90aGluZ0hhcHBlbmVkKSBdICsrPGJyPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
>> OyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyBpZiBkLnN0YXRlID09
>> IFJ1bm5pbmcgdGhlbjxicj4mbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJz
>> cDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsmbmJzcDsgWyBBbmlt
>> YXRpb25GcmFtZS5kaWZmcyBUaWNrPGJyPiZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZu
>> YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
>> OyAsIEtleWJvYXJkLmRvd25zIChcYyAtJmd0OyBpZiBDaGFyLmZyb21Db2RlIGMgPT0gJyAnIHRo
>> ZW4gSnVtcERvd24gZWxzZSBOb3RoaW5nSGFwcGVuZWQpPGJyPiZuYnNwOyZuYnNwOyZuYnNwOyZu
>> YnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNwOyZuYnNw
>> OyZuYnNwOyZuYnNwOyAsIEtleWJvYXJkLnVwcyAoXGMgLSZndDsgaWYgQ2hhci5mcm9tQ29kZSBj
>> ID09ICcgJyB0aGVuIEp1bXBVcCBlbHNlIE5vdGhpbmdIYXBwZW5lZCk8YnI+Jm5ic3A7Jm5ic3A7
>> Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5ic3A7Jm5i
>> c3A7Jm5ic3A7Jm5ic3A7Jm5
>>
>
--
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 [email protected].
For more options, visit https://groups.google.com/d/optout.