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.

Reply via email to