Using elm higher order functions for keyboard events - functional-programming

I am trying to create a higher order function to create functions to capture only a specific key code. The code is inspired on Evan's onEnter function from his todomvc implementation which captures only the enter function.
onKeyCode : Int -> Msg -> Attribute Msg
onKeyCode keycode msg =
let
captureKey code =
if code == keycode then
msg
else
NoOp
in
on "keydown" (Json.map captureKey keyCode)
onEnter = onKeyCode 13
onEsc = onKeyCode 27
And now I want to add that to an input component in the viewer:
input
[ class "edit"
, id ("todo-" ++ toString item.uid)
, value item.message
, onInput (UpdateItem item.uid)
, onBlur (SwitchEditTodo item.uid False)
, onEnter (SwitchEditTodo item.uid False)
, onEsc (UndoEditTodo item.uid)
]
[]
If I only have the onEnter the code will work as expected but if I add the onEsc, the onEnter code is never executed. Where am I doing the mistake? is that a problem with the higher order function context or "on" mapping with multiple values in separate functions?

You are adding two onkeydown attributes to the input element, and only one of them can win. The second in the list overwrites the first. Were it to use addEventListener behind the scenes, this would not be the case, but for now we can solve it with a slightly different approach.
You could write a onKeysDown function that accepts a list of possible key codes and the message they should invoke like this:
onKeysDown : List (Int, Msg) -> Attribute Msg
onKeysDown keys =
let
captureKey code =
List.filterMap (\(k, m) -> if k == code then Just m else Nothing) keys
|> List.head
|> Maybe.withDefault NoOp
in
on "keydown" (Json.map captureKey keyCode)
You could then write shorthand functions for handling specific keys like this:
enter msg = (13, msg)
esc msg = (27, msg)
And now you can use it in your view like this:
input
[ ...
, onKeysDown
[ enter <| SwitchEditTodo item.uid False
, esc <| UndoEditTodo item.uid
]
]
This works because it generates a single keydown event handler attribute. And while you substitute a predefined tuple for a higher order function, it still gives you just as readable code.

Related

How to return a single element from a Vec from a function?

I'm new to Rust, and I'm trying to make an interface where the user can choose a file by typing the filename from a list of available files.
This function is supposed to return the DirEntry corresponding to the chosen file:
fn ask_user_to_pick_file(available_files: Vec<DirEntry>) -> DirEntry {
println!("Which month would you like to sum?");
print_file_names(&available_files);
let input = read_line_from_stdin();
let chosen = available_files.iter()
.find(|dir_entry| dir_entry.file_name().into_string().unwrap() == input )
.expect("didnt match any files");
return chosen
}
However, it appears chosen is somehow borrowed here? I get the following error:
35 | return chosen
| ^^^^^^ expected struct `DirEntry`, found `&DirEntry`
Is there a way I can "unborrow" it? Or do I have to implement the Copy trait for DirEntry?
If it matters I don't care about theVec after this method, so if "unborrowing" chosen destroys the Vec, thats okay by me (as long as the compiler agrees).
Use into_iter() instead of iter() so you get owned values instead of references out of the iterator. After that change the code will compile and work as expected:
fn ask_user_to_pick_file(available_files: Vec<DirEntry>) -> DirEntry {
println!("Which month would you like to sum?");
print_file_names(&available_files);
let input = read_line_from_stdin();
let chosen = available_files
.into_iter() // changed from iter() to into_iter() here
.find(|dir_entry| dir_entry.file_name().into_string().unwrap() == input)
.expect("didnt match any files");
chosen
}

Xamarin Forms: Tap Event Args Derived Type

I have some code like this that works fine:
type App() =
inherit Application()
let stack = StackLayout(VerticalOptions = LayoutOptions.Center)
let label = Label(XAlign = TextAlignment.Center, Text = "Welcome to F# Xamarin.Forms!")
do
let tapRecognizer = new TapGestureRecognizer()
let handleTapEvent (sender:Object) (args:EventArgs) =
label.Text <- "Tapped at " + DateTime.Now.ToString()
()
let tapEventHandler = new EventHandler(handleTapEvent)
tapRecognizer.Tapped.AddHandler(tapEventHandler)
label.GestureRecognizers.Add(tapRecognizer)
However when I change the args from EventArgs to a derived type like this:
type TapEventArgs(someId:int) =
inherit EventArgs()
member this.SomeId = someId
let handleTapEvent (sender:Object) (args:TapEventArgs) =
label.Text <- args.SomeId.ToString() + " tapped"
()
I get the following error when I call AddHandler
The type 'EventArgs' is not compatible with the type 'TapEventArgs'
Also, If I change the EventHandler like this:
let tapEventHandler = new EventHandler<TapEventArgs>(handleTapEvent)
I get this error
This expression was expected to have type 'EventHandler'
but here has type 'EventHandler<TapEventArgs>'
Any way to force that derived type?
F# does not insert downcasts automatically the way C# does (and this is a good thing, not a bug). You cannot pass a descendant type where an ancestor type is expected.
In order to call AddHandler you need to insert a downcast manually using the downcast operator :>, like this:
tapRecognizer.Tapped.AddHandler(tapEventHandler :> EventHandler<EventArgs>)
When the target type is already known (like in your case), you can use an underscore in its place to let the F# compiler infer it from the context:
tapRecognizer.Tapped.AddHandler(tapEventHandler :> _)
The problem here is that the types are different, and that is what F# is telling you. The type of tapRecognizer.Tapped is of EventHandler, so when it is invoked it will be of type EventHandler ie not EventHandler<TapEventArgs> which is a different type. There is no way to change this, and subclassing TapGestureRecognizer is also not possible as the class is sealed.
Additionally, the code you posted would be difficult to compile, as it has circular references which F# prevents. TapEventArgs requires label which is defined in App. App depends on TapEventArgs. It would not be possible to update the UI from TapEventArgs instead a function would need to be passed in, or the state exposed.
There is a solution using the Command pattern, which allows some information to be passed to the callback and avoids circular dependencies. TapGestureRecognizer has a property CommandParameter where a value (of type obj) can be set. A callback can be supplied via the Command property that can receive that value. Here is the full example:
open Xamarin.Forms
open System
type App() as this =
inherit Application()
let stack = StackLayout(VerticalOptions = LayoutOptions.Center)
let label = Label(XAlign = TextAlignment.Center, Text = "Welcome to F# Xamarin.Forms!")
do
let tapRecognizer = new TapGestureRecognizer()
let handleTapEvent (x:obj) =
match x with
| :? int as someId -> label.Text <- someId.ToString() + " tapped"
| _ -> label.Text <- "Tapped at " + DateTime.Now.ToString()
tapRecognizer.Command <- new Command(Action<obj>(fun x -> handleTapEvent x))
label.GestureRecognizers.Add(tapRecognizer)
stack.Children.Add label
tapRecognizer.CommandParameter <- 42 // The value to be passed to the Command's callback
this.MainPage <- ContentPage(Content = stack)
Note that casting must be used, because of the way the types are defined in Xamarin.Forms (using obj for the property).

How to communicate with a polymorphic child component in Elm?

My main program has an update function of
update : Msg -> Model -> ( Model, Cmd Msg )
To communicate with sub-components we can add another variant and wrap our messages in a new message
type alias Model =
{ ...
, child : Child.Model
}
type Msg
= ...
| ChildMsg Child.Msg
update msg model =
case msg of
...
ChildMsg childMsg ->
let
( childModel, cmd ) =
Child.update childMsg model.child
updatedModel =
{ model | child = childModel }
childCmd =
Cmd.map ChildMsg cmd
in
( updatedModel, childCmd )
However this seem challenging if the type of my sub-component's update function does not match the parent. Consider a child with a polymorphic update function:
-- PolymorphicChild.elm
update : Msg a -> Model -> ( Model, Cmd (Msg a) )
When running a command from this module, I must wrap it
PolymorphicChild.someCommand : Cmd (Msg Foo)
PolymorphicChild.someCommand
|> Cmd.map PolymorphicChild
However, this produces a Msg (PolymorphicChild.Msg Foo), not the Msg PolymorphicChild.Msg my App is expecting.
The right side of (|>) is causing a type mismatch.
(|>) is expecting the right side to be a:
Cmd (PolyMorphicChild.Msg Foo) -> a
But the right side is:
Cmd Polymorphic.Msg -> Cmd Msg
I tried adding a polymorphic parameter to App.Msg
-- App.elm
type Msg a =
= ..
| PolymorphicChildMsg (PolymorphicChild.Msg a)
But it basically blows up my entire program. Every function involving App.Msg needs to somehow be changed to work with the new child component.
How can I unify the two types and get the two components working together?
I think the problem is that you're leaking too much information in your publicly exposed Msg type. Your use of the type parameter of Msg a seems limited to a known set of types, either an Author, Category, Post, or Tag. From skimming your code, it looks like it will never be anything but one of those four, so the fact that you are abstracting things in this manner should be kept inside of this module rather than exposing it and burdening any other code that may be pulling this in.
I think you need to move the abstraction down a level to avoid parameterizing your public Msg type. I would suggest having four concrete constructors for Msg instead of parameterizing it, and shift the abstraction down to a helper LoadInfo a type:
type alias LoadInfo a =
{ worker : Worker a
, url : Url
, result : Result Http.Error ( Int, List a )
}
type Msg
= LoadPost (LoadInfo Post)
| LoadCategory (LoadInfo Category)
| LoadTag (LoadInfo Tag)
| LoadAuthor (LoadInfo Author)

How does the Bool from `targetChecked` get turned into an `Action`?

In the Elm checkboxes example an Action is passed to the tag argument of the checkbox function (lines 51-53).
I don't understand how the type signature for this argument is (Bool -> Action) and how on line 69 it's able to use the function composition operator << to transform the Bool from targetChecked into the complete Action type.
EDIT:
This question can be reduced down to "why does the following work?"
type Action = Edit Int
do : (Int -> Action) -> Action
do tag = tag(123)
result : Action
result = do(Edit)
When you define a union type, each tag of the union type becomes a defined value. So when you define:
type Action = Tick | NoOp
this also defines:
Tick : Action
NoOp : Action
When the union tag has arguments, it becomes a "constructor", a function:
type Action = Edit Int
Edit : Int -> Action
(These tags are also used as patterns that you can match on with the case-of construct. See also the documentation on the website. )

F# Pattern-matching & recursion vs looping & if..then's for parsing nested structures

I'm using a 3rd party vendor's API in F#. On initialization the API returns a C# object that is nested msg container. It is populated with status messages and may include errors message. The vendor provides a C# sample parsing routine which I have ported F#.
The code sample loops through a nested msg container extracting fatal and nonfatal errors, and then return a List of tuples of type BBResponseType * string
Response Enum:
type BBResponseType =
| Status = 0
| Data = 1
| Error = 2
| FatalError = -1
My port to F# looks like this:
member private this.ProcessStatusMsg(eventObj: Blpapi.Event) =
let responseLst = List<(BBResponseType * string)>()
for msg in eventObj do
if msg.MessageType.Equals(SUBSTARTED) then
if msg.GetElement(EXCEPTIONS).NumValues > 0 then // <- check for errors/exceptions
let e = msg.GetElement(EXCEPTIONS)
for i in 0..e.NumValues-1 do
let error = e.GetValueAsElement(i)
let field = error.GetElementAsString(FieldID)
let reason = error.GetElement(REASON)
let message = sprintf "Subscription Started w/errors( Field: %s \n Reason: %s)" field (reason.GetElementAsString(DESCRIPTION))
responseLst.Add(BBResponseType.Error, message)
else
let message = sprintf "Subscription Started"
responseLst.Add(BBResponseType.Status, message)
if msg.MessageType.Equals(SUBSCFAILURE) then // <- check for subscriptions failure
if msg.HasElement(REASON) then
let reason = msg.GetElement(REASON)
let desc = reason.GetElementAsString(DESCRIPTION)
let message = sprintf "Real-time Subscription Failure: %s" desc
responseLst.Add(BBResponseType.FatalError, message)
else
let message = sprintf "Subscription Failure: (reason unknown) "
responseLst.Add(BBResponseType.FatalError, message)
responseLst
After I finished it, I looked at it and thought, "Wow, that's about as non-functional as you can get and still code in F#."
It does seem a lot clearer and succinct than the C# version, but I was thinking that there must be a better way to do all this without using so many loops and if/then's.
How can I do a better job of parsing these nested structures using pattern matching and recursion?
Few pointers:
Instead of returning a List of tuple return a seq of tuple - using the seq { } computation expression for creating sequence.
Extract the if/else parts as a function of type Message -> (BBResponseType * string) and use this function inside the seq expression
Inside this new function (which transforms the Message to tuple) use pattern matching to figure out what kind of (BBResponseType * string) to return.
To complement #Ankur's answer:
member private this.ProcessStatusMsg(eventObj: Blpapi.Event) =
// 0. Define a parameterized active pattern to turn if/else into pattern matching
let (|Element|_|) e msg =
if msg.HasElement(e) then
Some <| msg.GetElement(e)
else None
// 1. Wrapping the whole method body in a sequence expression
seq {
for msg in eventObj do
// 2. Extracting if/else part and using it in sequence expression
match msg.MessageType with
// 3. Using pattern matching to figure out what kind (BBResponseType * string) to return
| SUBSTARTED ->
match msg with
// 4. Use active pattern to pattern match on message directly
| Element EXCEPTIONS e when e.NumValues > 0 ->
for i in 0..e.NumValues-1 do
let error = e.GetValueAsElement(i)
let field = error.GetElementAsString(FieldID)
let reason = error.GetElement(REASON)
let message = sprintf "Subscription Started w/errors( Field: %s \n Reason: %s)" field (reason.GetElementAsString(DESCRIPTION))
yield (BBResponseType.Error, message)
| _ ->
let message = sprintf "Subscription Started"
yield (BBResponseType.Status, message)
| SUBSCFAILURE ->
match msg with
| Element REASON reason ->
let desc = reason.GetElementAsString(DESCRIPTION)
let message = sprintf "Real-time Subscription Failure: %s" desc
yield (BBResponseType.FatalError, message)
| _ ->
let message = sprintf "Subscription Failure: (reason unknown) "
yield (BBResponseType.FatalError, message)
// There are probably more cases, processing them here
| _ -> ()
}
Point 1, 2 and 3 in comments are from the other answer. I added point 0 and 4 to use active patterns for easy pattern matching.

Resources