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 elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to