In suave.io we can use choose combinator that has the Types.WebPart list -> Types.WebPart type.
Examples from their website show that I can use this combinator like this:
choose
[ path "/hello" >>= OK "Hello GET"
path "/goodbye" >>= OK "Good bye GET" ]
This list notation seems strange as it doesn't demand semicolon separating the elements. Yet, I have not been able to use it this way in different context.
So the following works:
> choose
[OK ""
OK ""];;
val it : Types.WebPart = <fun:choose#47>'
as well as
> choose [OK "" ;OK ""];;
val it : Types.WebPart = <fun:choose#47>
But the following don't compile:
>choose [OK "" OK ""];; //ERROR
> [OK ""
OK ""];; //ERROR
So, how does this notation work?
If you look at your last example
[OK ""
OK ""]
you should see that the in last line: OK "" is not directly below the OK in the previous line: [OK "" (it's one of to the left)
This should give you a hint ;)
You just have to align the elements in the same column (recommended: just use spaces)
this is why you usually write
[
OK ""
OK ""
]
instead of beginning the first element after [ - or some like
[ OK ""
; OK "" ]
too but I think that's not idiomatic F#.
remark
this also works with record syntax:
{
surname = "Smith"
givenname = "Adam"
}
Related
I am using the PEST parser and I am testing a simple example to get familiar with the syntax. I am trying to get every instance of ++ throughout the string but I am running into some issues. I think it may be an issue with the ANY keyword but I am not sure. Can anyone help point me in the right direction as to what is going wrong?
Here is my grammar.pest file
incrementing = {(prefix ~ ANY+ ~ "++" ~ suffix)}
prefix = {(NEWLINE | WHITESPACE)*}
suffix = {(NEWLINE | WHITESPACE)*}
WHITESPACE = _{ " " }
Here is my test case
//parses a file a matching rule and returns all instances of the rule
fn parse_file_contents_for_rule(rule: Rule, file_contents: &str) -> Option<Pairs<Rule>> {
SolgaParser::parse(rule, file_contents).ok()
}
fn parse_incrementing(file_contents: &str) {
//parse the file for the rule
let targets = parse_file_contents_for_rule(Rule::incrementing, file_contents);
//if there are matches
if targets.is_some() {
//iterate through all of the matches
for target in targets.unwrap().into_iter() {
println!("{}", target.as_str());
}
}
}
#[test]
fn test_parse_incrementing() {
let file_contents = r#"
index++;
a_thing++;
another_thing++;
should_not_match;
should_match++;
"#;
parse_incrementing(file_contents);
}
In your example, ANY+ is probably matching till the end of the line, so the ++ pattern is never matched, and therefore the whole incrementing rule is never matched.
Try changing it to (!"+" ~ ANY)+
I am formatting a web application made using F# and the SAFE stack. I am using a variable to determine a CSS class to change the formatting of a tag, but I also need two hard-coded CSS classes, and I am unsure how to have both.
I have this:
let statusTag (state:Appointment.State) =
span [ Class (state.ToString()) ] [ str (sprintf "%A" state) ]
And i need it to work more like this:
let statusTag (state:Appointment.State) =
span [ Class "status text" + (state.ToString()) ] [ str (sprintf "%A" state) ]
But i dont know how to do this in F#
Any help would be appreciated
The only thing that seems wrong with your attempt is that you need extra parentheses around the expression that constructs the string with the names of the classes (on the other hand, you do not need it around the state.ToString() call). The following should do the trick:
let statusTag (state:Appointment.State) =
span [ Class("status text" + state.ToString()) ] [ str (sprintf "%A" state) ]
in C++ you can go a switch / case construct and omit the break in a case statement to have the execution fall though the next case.
in C#, this is done with goto case.
Can this be done in F#?
A C# example to illustrate:
switch (a)
case "a":
...
break;
case "b":
...
goto case "a"
case "c":
...
I would imagine something like:
match x with
| "a" -> ...
| "b" -> ... + goto "a"
a practical example would be a case where:
"a" does some operation
"b" resets a counter and then does the same operation as "a"
and you'd want to avoid code duplication, but also to put the code in an external function.
F# is an expression based language, therefore it doesn't have imperative features like goto.
However, you can still express the same logic. First of all, you can combine 'cases':
let test str =
match str with
| (null|"") -> printf "empty"
| str -> printf "String: [%s]" str
And of course if you want to reuse just a part of some case logic, you can extract that in a local function:
let test str =
let onEmpty() = printf "empty!!!"
match str with
| null ->
onEmpty()
printf "null!"
| "" -> onEmpty()
| str -> printf "String [%s]" str
let aFun() = ...
let bFun() = ...
let abFun() = aFun >> bFun
or like this, which one is better for your situation
let abFun() =
aFun() |> ignore
bFun()
F# constrains you to do things more functional. goto is imperative operator
match x with
| "a" -> aFun()
| "b" -> abFun()
I'm parsing a string separated by newlines. For that, I have:
for line in str.Split([|Environment.NewLine|], StringSplitOptions.None) do
which gives me each line fine. What I'd like to do is take line and, if it starts with a certain string, add the remainder to a dictionary with the starting string as the key. Essentially, I want to implement the following logic in F#:
if line equals "[end]" then
break
else if line startsWith "string1" then
add the rest of line to a dictionary with the key "string1"
else if line startsWith "string2" then
add the rest of line to a dictionary with the key "string2"
else
continue
From what I've found, I should use a match..with statement to do this instead of transliterating that to F#, along the lines of this.
So far I have:
open System
open System.IO
open System.Collections.Generic
let str =
"Some string that
spans multiple lines
with prefixes
[end]"
let (|Prefix|_|) (p:string) (s:string) =
if s.StartsWith(p) then
Some(s.Substring(p.Length))
else
None
let dict = new Dictionary<string, string>();
for line in str.Split([|Environment.NewLine|], StringSplitOptions.None) do
match line with
| Prefix "[end]" -> dict // stop searching
| Prefix "spans" rest -> dict.Add("spans", rest) // add to dictionary
| _ -> () // continue searching
Which gives me the following error, which I'm not sure how to handle:
test.fs(20,5): error FS0001: Type mismatch.
Expecting a string -> 'a option but given a string -> string -> string option
The type ''a option' does not match the type 'string -> string option'
I'm using MonoDevelop/the open source F# compiler if that matters for anything, but I don't think it would.
So there were a few mistakes that I fixed:
The string literal should be
let str =
"Some string that
spans multiple lines
with prefixes
[end]"
or otherwise you get some spaces at the start of each line that you don't want
The match should look like
for line in str.Split([|Environment.NewLine|], StringSplitOptions.None) do
match line with
| Prefix "[end]" rest -> ()
| Prefix "spans" rest -> dict.Add("spans", rest)
| _ -> ()
Here, F# doesn't really have something like break so I have left the first and last cases doing nothing. I think this should do what you want.
I am a newb to F#, just began learning it this afternoon.
What I've noticed is that when getting type info via the fsi, I get the following info:
val it : (char list -> string -> string list) = <fun:clo#0>
If I understand correctly, the (char list -> string -> string list) means that the function takes a list of char and returns a function that takes a string and returns a list of string.
However, I don't understand the usage of the "it".
Thanks for any info!
In the F# interactive command line, "it" is an identifier that gets bound to the last expression evaluated. For example:
> let a = 5;;
val a : int = 5
> a;;
val it : int = 5
> it;;
val it : int = 5
>
It's not a keyword. Here's the F# keyword list.
Info on the val keyword:
The val keyword is used to declare a field in a class or structure type without initializing it. Fields declared in this manner are called explicit fields.
[ static ] val [ mutable ] [ access-modifier ] field-name : type-name
So the it normally is the field name.
In the interactive console it's the return value (val) (the name is irrelevant, they just call it "it"):
> System.Console.ReadLine();;
Test
val it : string = "Test"
> it;;
val it : string = "Test"
"it" is sometimes used as a placeholder argument name (for example, arguments to anonymous blocks). It's (no pun intended ;-) just a convention AFAIK.