I have a text input, and I've managed to debounce input. However, my keypress listener won't wait for text input events to flush before processing the enter key which would end edits without getting the latest value in the uncontrolled component.
Since I'm in webpack, React... is undefined so I can't just React.createRef() The current source code shows the function exists https://github.com/fable-compiler/fable-react/blob/e904add886bab45003c074cd2b06b8834fddf65b/src/Fable.React.Helpers.fs#L366
However it doesn't resolve/compile.
paket.lock shows Fable.React 4.1.3, Fable.Elmish.React 2.1.
createRef is available only since version 5.x something so you need to update to latest version. To be sure, I encourage you to upgrade to the latest version at the time of writing 5.2.3.
This means you will need to upgrade your application to Fable.Core v3, you can read more about it here.
When done you can use createRef like that:
open Fable.React
open Fable.React.Props
type MapComponent(initProps) =
inherit Fable.React.Component<MapComponentProps, obj>(initProps)
let mapRef : IRefHook<Browser.Types.HTMLDivElement option> = createRef None
override this.render() =
div [ RefValue mapRef ]
[ str "..." ]
As it turned out, for what I needed, the ref wasn't necessary, however I did get one going.
type IReactRef =
inherit Browser.Element
[<Emit("React.createRef")>]
let createRef(): IReactRef = jsNative
type TextInputProps =
{ Ident: string
Delay: int
AddedAttributes: IHTMLProp list
DefaultValue: string option
OnChange: (string -> unit)
OnEscape: (unit -> unit) option
OnEnter: (string -> unit) option
}
type TextInputState = InputState
let textInputDelayDefault = 500
type TextInputComponent(props) =
inherit React.Component<TextInputProps, TextInputState>(props)
let mutable textInput: obj = null
let debouncer = Eventing.Debouncer<string>.Create props.Ident props.Delay
do
textInput <- react.createRef()
base.setInitState InputState
member __.TextInput: IReactRef option =
textInput
|> Option.ofObj
|> Option.map unbox
// provide cancel edit extension point (Escape doesn't fire keypress)
member this.OnKeyUp(e: React.KeyboardEvent) =
if e.key = "Escape" then
match this.props.OnEscape with
| Some f ->
e.preventDefault()
f()
| None -> ()
// provide finish edit extension point
member this.OnKeyPress(e: React.KeyboardEvent) =
let value =
e
|> unbox
|> Eventing.getTargetValue
if e.key = "Enter" then
this.props.OnEnter
|> Option.iter (fun f ->
e.preventDefault()
debouncer.Clear()
// send the current value in case the onChange did not send the current value due to debouncing
f value)
override this.render() =
let r =
input [ yield R.Props.Ref(unbox textInput)
yield R.Props.OnKeyPress this.OnKeyPress
yield R.Props.OnKeyUp this.OnKeyUp
yield Eventing.onDebChange debouncer this.props.OnChange
yield R.Props.DefaultValue(this.props.DefaultValue |> Option.defaultValue "")
yield! this.props.AddedAttributes ]
r
let inline textInputComponent props = Fable.Helpers.React.ofType<TextInputComponent, _, _> props []
Related
I would like to write a function that enforces that its argument is, syntactically, a constant string. Here's what I tried:
module Test
module R = FStar.Reflection
let is_literal (t: R.term) =
match R.inspect_ln t with
| R.Tv_Const (R.C_String _) -> true
| _ -> false
let check_literal (s: string { normalize (is_literal (`s)) }) =
()
let test () =
check_literal ""; // should work
let s = "" in
check_literal s // should not work
However, I'm pretty sure static quotations (with `) are not what I want, but instead dynamic quotations with quote. But this would put my precondition into the Tac effect. Is there any way to do what I want in the current state of things?
I don't know if you finally found a solution, but what about implicit meta arguments?
They somehow allow running Tac code at function invocation time, making quote usable.
Changing your code a bit doing so seems to work:
module Is_lit
open FStar.Tactics
let is_literal (t: term) =
match inspect_ln t with
| Tv_Const (C_String _) -> true
| _ -> false
let check_literal (s: string)
(#[(if (normalize_term (is_literal (quote s)))
then exact (`())
else fail "not a litteral")
] witness: unit)
: unit =
()
// success
let _ = check_literal "hey"
// failure
[#expect_failure]
let _ = let s = "hey" in check_literal s
I am C# dev that has just starting to learn F# and I have a few questions about unit testing. Let's say I want to the following code:
let input () = Console.In.ReadLine()
type MyType= {Name:string; Coordinate:Coordinate}
let readMyType =
input().Split(';')
|> fun x -> {Name=x.[1]; Coordinate = {
Longitude = float(x.[4].Replace(",","."))
Latitude =float(x.[5].Replace(",","."))
}}
As you can notice, there are a few points to take in consideration:
readMyType is calling input() with has a side effect.
readMyType assume many thing on the string read (contains ';' at least 6 columns, some columns are float with ',')
I think the way of doing this would be to:
inject the input() func as parameter
try to test what we are getting (pattern matching?)
Using NUnit as explained here
To be honest I'm just struggling to find an example that is showing me this, in order to learn the syntax and other best practices in F#. So if you could show me the path that would be very great.
Thanks in advance.
First, your function is not really a function. It's a value. The distinction between functions and values is syntactic: if you have any parameters, you're a function; otherwise - you're a value. The consequence of this distinction is very important in presence of side effects: values are computed only once, during initialization, and then never change, while functions are executed every time you call them.
For your specific example, this means that the following program:
let main _ =
readMyType
readMyType
readMyType
0
will ask the user for only one input, not three. Because readMyType is a value, it gets initialized once, at program start, and any subsequent reference to it just gets the pre-computed value, but doesn't execute the code over again.
Second, - yes, you're right: in order to test this function, you'd need to inject the input function as a parameter:
let readMyType (input: unit -> string) =
input().Split(';')
|> fun x -> {Name=x.[1]; Coordinate = {
Longitude = float(x.[4].Replace(",","."))
Latitude =float(x.[5].Replace(",","."))
}}
and then have the tests supply different inputs and check different outcomes:
let [<Test>] ``Successfully parses correctly formatted string``() =
let input() = "foo;the_name;bar;baz;1,23;4,56"
let result = readMyType input
result |> should equal { Name = "the_name"; Coordinate = { Longitude = 1.23; Latitude = 4.56 } }
let [<Test>] ``Fails when the string does not have enough parts``() =
let input() = "foo"
(fun () -> readMyType input) |> shouldFail
// etc.
Put these tests in a separate project, add reference to your main project, then add test runner to your build script.
UPDATE
From your comments, I got the impression that you were seeking not only to test the function as it is (which follows from your original question), but also asking for advice on improving the function itself, so as to make it more safe and usable.
Yes, it is definitely better to check error conditions within the function, and return appropriate result. Unlike C#, however, it is usually better to avoid exceptions as control flow mechanism. Exceptions are for exceptional situations. For such situations that you would have never expected. That is why they are exceptions. But since the whole point of your function is parsing input, it stands to reason that invalid input is one of the normal conditions for it.
In F#, instead of throwing exceptions, you would usually return a result that indicates whether the operation was successful. For your function, the following type seems appropriate:
type ErrorMessage = string
type ParseResult = Success of MyType | Error of ErrorMessage
And then modify the function accordingly:
let parseMyType (input: string) =
let parts = input.Split [|';'|]
if parts.Length < 6
then
Error "Not enough parts"
else
Success
{ Name = parts.[0]
Coordinate = { Longitude = float(parts.[4].Replace(',','.')
Latitude = float(parts.[5].Replace(',','.') }
}
This function will return us either MyType wrapped in Success or an error message wrapped in Error, and we can check this in tests:
let [<Test>] ``Successfully parses correctly formatted string``() =
let input() = "foo;the_name;bar;baz;1,23;4,56"
let result = readMyType input
result |> should equal (Success { Name = "the_name"; Coordinate = { Longitude = 1.23; Latitude = 4.56 } })
let [<Test>] ``Fails when the string does not have enough parts``() =
let input() = "foo"
let result = readMyType input
result |> should equal (Error "Not enough parts)
Note that, even though the code now checks for enough parts in the string, there are still other possible error conditions: for example, parts.[4] may be not a valid number.
I am not going to expand on this further, as that will make the answer way too long. I will only stop to mention two points:
Unlike C#, verifying all error conditions does not have to end up as a pyramid of doom. Validations can be nicely combined in a linear-looking way (see example below).
The F# 4.1 standard library already provides a type similar to ParseResult above, named Result<'t, 'e>.
For more on this approach, check out this wonderful post (and don't forget to explore all links from it, especially the video).
And here, I will leave you with an example of what your function could look like with full validation of everything (keep in mind though that this is not the cleanest version still):
let parseFloat (s: string) =
match System.Double.TryParse (s.Replace(',','.')) with
| true, x -> Ok x
| false, _ -> Error ("Not a number: " + s)
let split n (s:string) =
let parts = s.Split [|';'|]
if parts.Length < n then Error "Not enough parts"
else Ok parts
let parseMyType input =
input |> split 6 |> Result.bind (fun parts ->
parseFloat parts.[4] |> Result.bind (fun lgt ->
parseFloat parts.[5] |> Result.bind (fun lat ->
Ok { Name = parts.[1]; Coordinate = { Longitude = lgt; Latitude = lat } } )))
Usage:
> parseMyType "foo;name;bar;baz;1,23;4,56"
val it : Result<MyType,string> = Ok {Name = "name";
Coordinate = {Longitude = 1.23;
Latitude = 4.56;};}
> parseMyType "foo"
val it : Result<MyType,string> = Error "Not enough parts"
> parseMyType "foo;name;bar;baz;badnumber;4,56"
val it : Result<MyType,string> = Error "Not a number: badnumber"
This is a little follow-up to the excellent answer of #FyodorSoikin trying to explore the suggestion
keep in mind though that this is not the cleanest version still
Making the ParseResult generic
type ParseResult<'a> = Success of 'a | Error of ErrorMessage
type ResultType = ParseResult<Defibrillator> // see the Test Cases
we can define a builder
type Builder() =
member x.Bind(r :ParseResult<'a>, func : ('a -> ParseResult<'b>)) =
match r with
| Success m -> func m
| Error w -> Error w
member x.Return(value) = Success value
let builder = Builder()
so we get a concise notation:
let parse input =
builder {
let! parts = input |> split 6
let! lgt = parts.[4] |> parseFloat
let! lat = parts.[5] |> parseFloat
return { Name = parts.[1]; Coordinate = { Longitude = lgt; Latitude = lat } }
}
Test Cases
Tests are always fundamental
let [<Test>] ``3. Successfully parses correctly formatted string``() =
let input = "foo;the_name;bar;baz;1,23;4,56"
let result = parse input
result |> should equal (ResultType.Success { Name = "the_name"; Coordinate = { Longitude = 1.23; Latitude = 4.56 } })
let [<Test>] ``3. Fails when the string does not have enough parts``() =
let input = "foo"
let result = parse input
result |> should equal (ResultType.Error "Not enough parts")
let [<Test>] ``3. Fails when the string does not contain a number``() =
let input = "foo;name;bar;baz;badnumber;4,56"
let result = parse input
result |> should equal (ResultType.Error "Not a number: badnumber")
Notice the usage of a specific ParseResult from the generic one.
minor note
Double.TryParse is just enough in the following
let parseFloat (s: string) =
match Double.TryParse s with
| true, x -> Success x
| false, _ -> Error ("Not a number: " + s)
I have a function save that take standard input, which is used individually like this:
./try < input.txt (* save function is in try file *)
input.txt
2
3
10 29 23
22 14 9
and now i put the function into another file called path.ml which is a part of my interpreter. Now I have a problem in defining the type of Save function and this is because save function has type in_channel, but when i write
type term = Save of in_channel
ocamlc complain about the parameter in the command function.
How can i fix this error? This is the reason why in my last question posted on stackoverflow, I asked for the way to express a variable that accept any type. I understand the answers but actually it doesn't help much in make the code running.
This is my code:
(* Data types *)
open Printf
type term = Print_line_in_file of int*string
| Print of string
| Save of in_channel (* error here *)
;;
let input_line_opt ic =
try Some (input_line ic)
with End_of_file -> None
let nth_line n filename =
let ic = open_in filename in
let rec aux i =
match input_line_opt ic with
| Some line ->
if i = n then begin
close_in ic;
(line)
end else aux (succ i)
| None ->
close_in ic;
failwith "end of file reached"
in
aux 1
(* get all lines *)
let k = ref 1
let first = ref ""
let second = ref ""
let sequence = ref []
let append_item lst a = lst # [a]
let save () =
try
while true do
let line = input_line stdin in
if k = ref 1
then
begin
first := line;
incr k;
end else
if k = ref 2
then
begin
second := line;
incr k;
end else
begin
sequence := append_item !sequence line;
incr k;
end
done;
None
with
End_of_file -> None;;
let rec command term = match term with
| Print (n) -> print_endline n
| Print_line_in_file (n, f) -> print_endline (nth_line n f)
| Save () -> save ()
;;
EDIT
Error in code:
Save of in_channel:
Error: This pattern matches values of type unit
but a pattern was expected which matches values of type in_channel
Save of unit:
Error: This expression has type 'a option
but an expression was expected of type unit
There are many errors in this code, so it's hard to know where to start.
One problem is this: your save function has type unit -> 'a option. So it's not the same type as the other branches of your final match. The fix is straightforward: save should return (), not None. In OCaml these are completely different things.
The immediate problem seems to be that you have Save () in your match, but have declared Save as taking an input channel. Your current code doesn't have any way to pass the input channel to the save function, but if it did, you would want something more like this in your match:
| Save ch -> save ch
Errors like this suggest (to me) that you're not so familiar with OCaml's type system. It would probably save you a lot of trouble if you went through a tutorial of some kind before writing much more code. You can find tutorials at http://ocaml.org.
This works in F# Interactive:
let (list:(int * int) List) = []
list # [(40, 60)];;
This doesent work in my program:
let rMouseEvent =
form.MouseClick.Add(fun args -> list # [(args.X, args.Y)]))
Can someone explain why, and help me solve this?
The error says:
This expression was expected to have type
unit
but here has type
'a list -> 'a list
Your handler should not return a value, at present it returns an int * int list. You could ignore it using ignore:
let rMouseEvent = form.MouseClick.Add(fun args -> list # [(args.X, args.Y)] |> ignore)
although this is not very useful. If you want to add an item to list, you could change it to a ResizeArray:
let r = new ResizeArray<int * int>()
let rMouseEvent = form.MouseClick.Add(fun args -> r.Add((args.X, args.Y)))
alternatively you can use a ref:
let (r: (int*int) list ref) = ref []
let rMouseEvent = form.MouseClick.Add(fun args -> r := !r # [(args.X, args.Y)])
The compile error you get indicates that the event handler was expected to return unit - i.e. no value at all - but you're trying to return a (int * int) list. The expected return type indicates that the caller isn't going to look after the value you return for you, so you need to store any values you change yourself.
If you want to stick with using lists, then make your original list into ref:
let list : (int * int) List ref = ref []
and then do something like:
let rMouseEvent =
form.MouseClick.Add(fun args -> list := !list # [(args.X, args.Y)]))
Rust has a linear type system. Is there any (good) way to simulate this in OCaml? E.g., when using ocaml-lua, I want to make sure some functions are called only when Lua is in a specific state (table on top of stack, etc).
Edit: Here's a recent paper about resource polymorphism relevant to the question: https://arxiv.org/abs/1803.02796
Edit 2: There are also a number of articles about session types in OCaml available, including syntax extensions to provide some syntactic sugar.
As suggested by John Rivers, you can use a monadic style to represent
"effectful" computation in a way that hides the linear constraint in
the effect API. Below is one example where a type ('a, 'st) t is
used to represent computation using a file handle (whose identity is
implicit/unspoken to guarantee that it cannot be duplicated), will
product a result of type 'a and leave the file handle in the state
'st (a phantom type being either "open" or "close"). You have to use
the run of the monad¹ to actually do anything, and its type ensure
that the file handles are correctly closed after use.
module File : sig
type ('a, 'st) t
type open_st = Open
type close_st = Close
val bind : ('a, 's1) t -> ('a -> ('b, 's2) t) -> ('b, 's2) t
val open_ : string -> (unit, open_st) t
val read : (string, open_st) t
val close : (unit, close_st) t
val run : ('a, close_st) t -> 'a
end = struct
type ('a, 'st) t = unit -> 'a
type open_st = Open
type close_st = Close
let run m = m ()
let bind m f = fun () ->
let x = run m in
run (f x)
let close = fun () ->
print_endline "[lib] close"
let read = fun () ->
let result = "toto" in
print_endline ("[lib] read " ^ result);
result
let open_ path = fun () ->
print_endline ("[lib] open " ^ path)
end
let test =
let open File in
let (>>=) = bind in
run begin
open_ "/tmp/foo" >>= fun () ->
read >>= fun content ->
print_endline ("[user] read " ^ content);
close
end
(* starting with OCaml 4.13, you can use binding operators:
( let* ) instead of ( >>= ) *)
let test =
let open File in
let ( let* ) = bind in
run begin
let* () = open_ "/tmp/foo" in
let* content = read in
print_endline ("[user] read " ^ content);
close
end
Of course, this is only meant to give you a taste of the style of
API. For more serious uses, see Oleg's monadic
regions examples.
You may also be interested in the research programming language
Mezzo, which aims to
be a variant of ML with finer-grained control of state (and related
effectful patterns) through a linear typing discipline with separated
resources. Note that it is only a research experiment for now, not
actually aimed at users. ATS is also relevant,
though finally less ML-like. Rust may actually be a reasonable
"practical" counterpart to these experiments.
¹: it is actually not a monad because it has no return/unit combinator, but the point is to force type-controlled sequencing as the monadic bind operator does. It could have a map, though.