How to use Fields in Elm 0.13 - user-interface

I have been trying to get the fields to work, but keep failing. I have also been trying to look for examples, but the only examples I could find are using Elm 0.14, which use the new Channel API which isn't available in Elm 0.13.
So I started from the example offered in the catalog
import Graphics.Input.Field (..)
import Graphics.Input (..)
name : Input Content
name = input noContent
nameField : Signal Element
nameField = field defaultStyle name.handle identity "Name" <~ name.signal
And in order to use the field I tried
main : Signal Element
main = Signal.lift2 display Window.dimensions gameState
display : (Int,Int) -> GameState -> Element
display (w,h) g =
container w h middle <|
collage gameWidth gameHeight
(if | g.state == Menu ->
[ rect gameWidth gameHeight
|> filled black
, toForm nameField
, plainText "*The name entered in the nameField*"
]
| otherwise -> []
)
But I keep getting the following error
Expected Type: Signal.Signal Graphics.Element.Element
Actual Type: Graphics.Element.Element
Why isn't the element a signal anymore... The function definition clearly states it should output a signal, right? Now how would I be able to enter a name, that I would then be able to use inside a variable?

Elm 0.13 had some annoyingly confusing type error messages. Expected/Actual are usually swapped. In this case the problem comes from using nameField : Signal Element in display : (Int,Int) -> GameState -> Element. display is a pure (non-signal) function, but to be pure, you can't use a signal anywhere in there. To solve this, hoist the nameField signal up a level, to main. To use what is entered in the field, use the input signal:
main : Signal Element
main = Signal.lift4 display Window.dimensions gameState name.signal
nameField : Content -> Element
nameField = field defaultStyle name.handle identity "Name"
display : (Int,Int) -> GameState -> Content -> Element
display (w,h) g currentContent =
container w h middle <|
collage gameWidth gameHeight
(if | g.state == Menu ->
[ rect gameWidth gameHeight
|> filled black
, toForm (nameField currentContent) -- use something other than `currentContent` here to influence the field content.
, plainText currentContent.string
]
| otherwise -> []
)

Related

User-interface and Menu in Haskell

I am creating social network in haskell based on graphs. The problem is that I want to create a user interface for people to interact. This user interface should consists of text that shows what the options are and based on key inputs, users can search the database and perform actions on the data set.
What I have already done:
-Explored this thread "Simple text menu in Haskell"
-Installed packages such as haskelline
Problem is that I have just started learning Haskell and the progress has been damn slow compared to my experience with other languages, so I havent benefitted from the above resources to an extent that has solved my problem.
Would someone be kind enough to share a template consisting of a CL interface menu screen. That asks users to press keys mapped for different functions. Then after output, goes back to the main menu.
Here is an example of what my functions look like.
isFriend :: Node -> Node -> [Edge] -> Bool
isFriend _ _ [] = False
isFriend a b (x:xs)
| edgeCompare a b x == True = True
| otherwise = isFriend a b xs
So the menu could say "press I" to search for friends, that would prompt the user to enter a name. This would run my function with the argument inputted by the user.
Thank you :)
Based on this answer, I've created this:
import System.IO (stdin, hSetEcho, hSetBuffering, BufferMode(NoBuffering), hReady)
import Control.Monad (when)
getKey = reverse <$> getKey' ""
where getKey' chars = do
char <- getChar
more <- hReady stdin
(if more then getKey' else return) (char:chars)
-- Simple menu controller
main = do
hSetBuffering stdin NoBuffering
hSetEcho stdin False
key <- getKey
when (key /= "\ESC") $ do
case key of
"w" -> putStrLn "↑"
"s" -> putStrLn "↓"
"d" -> putStrLn "→"
"a" -> putStrLn "←"
"\n" -> putStrLn "⎆"
"\DEL" -> putStrLn "⎋"
_ -> return ()
main
[1] also shows how to detect arrow key presses, which is cool! Changing the line buffering of stdin is important.
You'll probably want your application loop to have some initial application state, and pass it around as an argument.

F# using match to validate parameters

I'm learning F#. I want to know best practices for validating input parameters. In my naivety I had thought I could do something like this:
let foo = match bar with
| <test for valid> -> bar
| _ -> "invalid"
of course that doesn't work due to mismatching types. So I'd like to see the patterns experienced F# programmers use for this sort of thing. match? If/then/else?
Something else?
You are having problems because you are trying to bind a value to something that could be two possible types depending upon program flow - that is incompatible with static typing.
If I have some value foo, it cannot be, for example, a string OR an int depending upon program flow; it must resolve to exactly one type at compile time.
You can, however, use a discriminated union that can represent several different options within a single type.
Here is a summary of the approaches for doing just that.
Result Type / Either
F# 4.1, which is currently available via nuget, introduces the Result type. You may find this type referred to as Either in other languages.
It is defined like this:
[<Struct>]
type Result<'T,'TError> =
/// Represents an OK or a Successful result. The code succeeded with a value of 'T.
| Ok of ResultValue:'T
/// Represents an Error or a Failure. The code failed with a value of 'TError representing what went wrong.
| Error of ErrorValue:'TError
If you are pre-F# 4.1 (which is very likely). You can define this type yourself, although you must remove the [<Struct>] attribute.
You can then make a tryParseFloat function:
let tryParseFloat str =
match System.Double.TryParse str with
| true, f -> Ok f
| _ -> Error <| sprintf "Supplied string (%s) is not a valid float" str
You can determine success or failure:
match tryParseFloat "0.0001" with
|Ok v -> // handle success
|Error err -> // handle error
In my opinion, this is the preferred option, especially in F# 4.1+ where the type is built in. This is because it allows you to include information relating to how and why some activity failed.
Option Type / Maybe
The option type contains either Some 'T or simply None. The option type is used to indicate the presence or absence of a value, None fills a role similar to null in other languages, albeit far more safely.
You may find this type referred to as Maybe in other languages.
let tryParseFloat str =
match System.Double.TryParse str with
| true, f -> Some f
| _ -> None
You can determine success or failure:
match tryParseFloat "0.0001" with
|Some value -> // handle success
|None -> // handle error
Composition
In both cases, you can readily compose options or results using the associated map and bind functions in the Option and Result modules respectively:
Map:
val map: mapping:('T -> 'U) -> option:'T option -> 'U option
val map : mapping:('T -> 'U) -> result:Result<'T, 'TError> -> Result<'U, 'TError>
The map function lets you take an ordinary function from 'a -> 'b and makes it operate on results or options.
Use case: combine a result with a function that will always succeed and return a new result.
tryParseFloat "0.001" |> Result.map (fun x -> x + 1.0);;
val it : Result<float,string> = Ok 1.001
Bind:
val bind: binder:('T -> 'U option) -> option:'T option -> 'U option
val bind: binder:('T -> Result<'U, 'TError>) -> result:Result<'T, 'TError> -> Result<'U, 'TError>
The bind function lets you combine results or options with a function that takes an input and generates a result or option
Use case: combine a result with another function that may succeed or fail and return a new result.
Example:
let trySqrt x =
if x < 0.0 then Error "sqrt of negative number is imaginary"
else Ok (sqrt x)
tryParseFloat "0.001" |> Result.bind (fun x -> trySqrt x);;
val it : Result<float,string> = Ok 0.0316227766
tryParseFloat "-10.0" |> Result.bind (fun x -> trySqrt x);;
val it : Result<float,string> = Error "sqrt of negative number is imaginary"
tryParseFloat "Picard's Flute" |> Result.bind (fun x -> trySqrt x);;
val it : Result<float,string> =
Error "Supplied string (Picard's Flute) is not a valid float"
Notice that in both cases, we return a single result or option despite chaining multiple actions - that means that by following these patterns you need only check the result once, after all of your validation is complete.
This avoids a potential readability nightmare of nested if statements or match statements.
A good place to read more about this is the Railway Oriented Programming article that was mentioned to you previously.
Exceptions
Finally, you have the option of throwing exceptions as a way of preventing some value from validating. This is definitely not preferred if you expect it to occur but if the event is truly exceptional, this could be the best alternative.
The basic way of representing invalid states in F# is to use the option type, which has two possible values. None represents invalid state and Some(<v>) represents a valid value <v>.
So in your case, you could write something like:
let foo =
match bar with
| <test for valid> -> Some(bar)
| _ -> None
The match construct works well if <test for valid> is actual pattern (e.g. empty list or a specific invalid number or a null value), but if it is just a boolean expression, then it is probably better to write the condition using if:
let foo =
if <test for valid> bar then Some(bar)
else None
You could do something along this lines
type Bar =
| Bar of string
| Foo of int
let (|IsValidStr|_|) x = if x = Bar "bar" then Some x else None
let (|IsValidInt|_|) x = if x = Foo 0 then Some x else None
let foo (bar:Bar) =
match bar with
| IsValidStr x -> Some x
| IsValidInt x -> Some x
| _ -> None
That is you could use active patterns to check for the actual business rules and return an Option instance
Based on what the OP wrote in the comments:
You would define a type as in the post that Fyodor linked, that captures your two possible outcomes:
type Result<'TSuccess,'TFailure> =
| Success of 'TSuccess
| Failure of 'TFailure
Your validation code becomes:
let checkBool str =
match bool.TryParse str with
| true, b -> Success b
| _ -> Failure ("I can't parse this: " + str)
When using it, again use match:
let myInput = "NotABool"
match checkBool myInput with
| Success b -> printfn "I'm happy: %O" b
| Failure f -> printfn "Did not like because: %s" f
If you only would like to continue with valid bools, your code can only fail on invalid arguments, so you would do:
let myValidBool =
match checkBool myInput with
| Success b -> b
| Failure f -> failwithf "I did not like the args because: %s" f

Creating a form with Elm

I would like to create a form in Elm that takes 4 required inputs:
3 floating point values
1 input which can take the values of "long" or "short" (presumably) this would be a drop-down
When the values are entered, a computation occurs that yields a single line of output based on these values.
I have this working as a command-line Python program:
#!/usr/bin/env python
from __future__ import print_function
# core
import logging
# pypi
import argh
# local
logging.basicConfig(
format='%(lineno)s %(message)s',
level=logging.WARN
)
def main(direction, entry, swing, atr):
entry = float(entry)
swing = float(swing)
atr = float(atr)
if direction == 'long':
sl = swing - atr
tp = entry + (2 * atr)
elif direction == 'short':
sl = swing + atr
tp = entry - (2 * atr)
print("For {0} on an entry of {1}, SL={2} and TP={3}".format(
direction, entry, sl, tp))
if __name__ == '__main__':
argh.dispatch_command(main)
but want to use Elm to create a web UI for it.
This isn't an ideal first introduction to Elm, since it takes you through a few of Elm's more difficult areas: mailboxes and the Graphics.Input library. There is also not an easy-to-deploy number input, so I've only implemented the dropdown; you'd use Graphics.Input.Field (which can get particularly dicey).
A mailbox is basically a signal that the dropdown input can send a message to. I've chosen for that message to be a function, specifically, how to produce a new state from the old one. We define state to be a record type (like a Python named tuple), so saving the direction involves storing the new direction in the record.
The text is rendered using a convenience function that makes it monospace. There's a whole text library you can use, but Elm 0.15 does not have string interpolation, so you're stuck with the quite ugly appends.
Finally, there's not much on an Elm community on SO, but you're welcome to join the mailing list where questions like this are welcomed. That being said, you really should try to dive into Elm and learn the basics so you can ask a more specific question. This is true of almost any language, library or framework - you have to do some basic exercises before you can write "useful" code.
import Graphics.Input as Input
import Graphics.Element as Element exposing (Element)
mailbox = Signal.mailbox identity
type Direction = Short | Long
type alias State = {entry : Float, swing : Float, atr : Float, dir : Direction}
initialState : State
initialState = State 0 0 0 Short
dropdown : Element
dropdown =
Input.dropDown
(\dir -> Signal.message mailbox.address (\state -> {state| dir <- dir}))
[("Short", Short), ("Long", Long)]
state : Signal State
state = Signal.foldp (<|) initialState mailbox.signal
render : State -> Element
render state =
dropdown `Element.above`
Element.show ("For "++(toString state.dir)++" on an entry of "++(toString state.entry) ++
", SL="++(toString (sl state))++" and TP="++(toString (tp state)))
main = Signal.map render state
-- the good news: these are separate, pure functions
sl {entry, swing, atr, dir} =
case dir of
Long -> swing - atr
Short -> swing + atr
tp {entry, swing, atr, dir} =
case dir of
Long -> entry + (2*atr)
Short -> entry - (2*atr)
Update: I wrote an essay on mailboxes and how to use them.

Why am I getting an error using List.map in F#?

Why does the F# compiler complain "RequireQualifiedAccess ..." for the Open statement and give an error for the use of List.map in:
open Microsoft.FSharp.Collections.Map
type Gen =
static member Calc (data : int[]) = data.List.map (fun x -> x + 1)
First of all, your open statement has nothing to to with List.map, it would open the Map module, which you cannot open but have to access explicitly with Map., hence the error. The Map module contains functions similar to the ones in the List module, but works with maps (similar to dictionaries in C#).
The function List.map ist just called that: List.map. It is standalone and not a part of your data object, which, by the way, you have defined to be an array with (data : int[]).
So I think the code you meant to write is:
type Gen =
static member Calc (data : List<int>) = data |> List.map (fun x -> x + 1)
And also note that the compiler is smart enough to deduce that data is a list of ints, so you can remove the type annotation if you like.

Mapping/translating an object to another in F#

I'm a beginner to F# and playing around with it, until I faced this problem. I searched for it but couldn't find anything. I want to mutate an object into another. I have Geolocation object With lots of properties, two of them the Latitude and Longitude. I want to create a new dynamic object but using a pipe or a select operator, with only that subset of properties
let customLocation = OtherPlace.Geolocation ....
how can I do this?
The best way to solve this sort of problem is to create a discriminated union with a single case. You could use a straight type alias, but you would lose a small amount of type safety. To define the type use:
type Loc = |LL of float * float
and then you can create instances with something like:
Something |> fun t -> LL(t.Latitude,t.Longitude)
or the simpler version:
LL(something.Latitude,something.Longitude)
let's say you have an array of OtherPlace.Geolocation
geoLocations : OtherPlace.Geolocation array
you can then, depending on your need :
use a tuple (which is just a special case of a record)
.
//of type (double * double) array
let g = geoLocations |> Array.map (fun x -> x.Latitude, x.Longitude)
create a record type (nb : a tuple is just a record with positional names)
.
type Position = {Latitude : double; Longitude : double}
//of type Position array
let g = geoLocations |> Array.map (fun x -> x.Latitude, x.Longitude)
For small local need, a tuple is better suited but can become unwieldy.
Records allow you to better structure the program
Union case should be used to differentiate between different things, that still represent some common concept.
For instance you could have the position to be expressed in different system
type GeoPosition = | LaTLong of double * double
| WGS84 of double * double
| ...
//of type GeoPosition array
let g = geoLocations |> Array.map (fun x -> LatLong (x.Latitude, x.Longitude))
PS : if you use F# 3.1 you have one additional sugar for naming union type fields as shown here

Resources