How do I do regular expressions using a functional approach? Currently I want the user entering an input and even if they enter it in capital letters it will still give a response? I am unsure of how to implement this.
open System
open System.Drawing
open System.Windows.Forms
let (|Hello|Bye|None|) input =
match input with
| "hello" | "hi" | "morning"
-> Hello
| "Goodbye" | "bye" | "go"
-> Bye
| _
-> None
let rand = new Random()
let hello_response () =
let n = rand.Next(10)
match n with
| 0 -> "How do you do."
| 1 -> "Is nice talking to you."
| 2 -> "Tell me something new."
| 3 -> "Nice to meet you."
| 4 -> "My pleasure."
| 5 -> "Hi."
| 6 -> "Hello."
| 7 -> "Good day."
| 8 -> "Salutation!"
| 9 -> "Welcome!"
let good_bye_response () =
let n = rand.Next(10)
match n with
| 0 -> "Talk to you soon."
| 1 -> "It was nice talking to you."
| 2 -> "Good bye."
| 3 -> "Stay a bit longer."
| 4 -> "Adios amigo."
| 5 -> "Bye."
| 6 -> "Adios."
| 7 -> "See you."
| 8 -> "Please don't go"
| 9 -> "Why are you leaving me alone?"
let none_response (str:string) =
let n = rand.Next(10)
match n with
| 0 -> "Maybe."
| 1 -> "Perhaps " + str
| 2 -> "Yes."
| 3 -> "Ah!"
| 4 -> "Whatever."
| 5 -> "Sorry, the chat closed unexpectedly. What was your last
question?"
| 6 -> "Where were we? I losed track of the conversation."
| 7 -> "Very interesting"
| 8 -> "Wow!"
| 9 -> "Mmmmmm!"
let rec response (token: string) (str: string) =
match token with
| Hello
-> hello_response ()
| Bye
-> good_bye_response ()
| ""
-> none_response str
| None when (str.IndexOf(" ") > 0)
-> response (str.Substring(0,str.IndexOf(" ")))
(str.Substring(str.IndexOf(" ")+1))
| None when (str.IndexOf(" ") < 0)
-> response str ""
| None
-> str
let marketbot_resp (str: string) =
if (str.IndexOf(" ") > 0) then
response (str.Substring(0,str.IndexOf(" ")))
(str.Substring(str.IndexOf(" ")+1)) + "\n"
else
response str "" + "\n"
You can use regular expressions from F# exactly the same way you would from C# or VB.NET (or any other .NET language). MSDN provides quite extensive documentation on the subject. Check it out.
The root class is System.Text.RegularExpressions.Regex. The simplest way to match is through the IsMatch static method:
let (|Hello|Bye|None|) input =
if Regex.IsMatch( input, "(?i)hello|hi|morning" ) then Hello
elif Regex.IsMatch( input, "(?i)goodbye|bye|go" ) then Bye
else None
You can also "cache" the regular expression by creating an instance of Regex and reusing it. This will save you a tiny bit on performance:
let (|Hello|Bye|None|) =
let hello = Regex "(?i)hello|hi|morning"
let bye = Regex "(?i)goodbye|bye|go"
fun input ->
if hello.IsMatch input then Hello
elif bye.IsMatch input then Bye
else None
However, for this particular task I think regular expressions are overkill. I would just convert the string to lower case before matching:
let (|Hello|Bye|None|) (input: string) =
match input.ToLower() with
| "hello" | "hi" | "morning"
-> Hello
| "goodbye" | "bye" | "go"
-> Bye
| _
-> None
Related
Haven't been able to find much online documentation regarding begin/end in ocaml. I have two different pattern matches in the same function (which I want to be independent of each other), but vscode is parsing them to nest the second inside the first. I've tried surrounding the first pattern match in begin/end, but it's giving me syntax errors:
begin match c.r with (* first pattern match *)
| [ r1; r2; r3 ] ->
let _ = print_endline (String.make 1 r3.top) in end
match cl with (* second pattern match *)
| [] -> []
I get a red underline on end that says Syntax error after unclosed begin, expecting expr. I do not understand what this means, since I wrote end to close the begin, so why is the begin unclosed? The code compiles fine without the begin/end (except that it nests the second pattern match inside the first one). Thanks.
In OCaml begin/end is essentially identical to open/close parentheses. Inside you should have a well-formed expression (as in pretty much any programming language).
What you have inside your begin/end is not an expression, since it ends wih in. A let expression looks like let pattern = expr1 in expr2. You are missing the second expression inside the begin/end.
What you should do (I think) is put begin/end around the inner match like this:
match c.r with
| [r1; r2; r3 ] ->
let _ = print_endline (String.make 1 r3.top) in
begin
match c1 with
| [] -> []
...
end
| ...
(This code doesn't make a lot of sense but I assume it's just an example.)
As another simplification you can change let _ = a in b to a; b if a is of unit type, as it is in your code.
What Jeffrey Scofield said. Consider how this can become confusing when we nest matches. How do we read the following?
match "foo" with
| "bar" -> 42
| "foo" ->
match "baz" with
| "baz" -> 27
| _ -> 19
| _ -> 33
The indentation makes it fairly clear how this is meant, but OCaml doesn't care about your pretty indentation. It could just as easily be that you meant:
match "foo" with
| "bar" -> 42
| "foo" ->
match "baz" with
| "baz" -> 27
| _ -> 19
| _ -> 33
Or:
match "foo" with
| "bar" -> 42
| "foo" ->
match "baz" with
| "baz" -> 27
| _ -> 19
| _ -> 33
Either parentheses or begin/end disambiguate this situation.
match "foo" with
| "bar" -> 42
| "foo" ->
(match "baz" with
| "baz" -> 27
| _ -> 19)
| _ -> 33
Or:
match "foo" with
| "bar" -> 42
| "foo" ->
begin
match "baz" with
| "baz" -> 27
| _ -> 19
end
| _ -> 33
One more thing...
Nested match expressions are often unnecessary. Consider when you have a nested match if you can't more cleanly express the same as a single level match on a tuple of values.
match a with
| X -> ...
| Y ->
(match b with
| Z -> ...
| W -> ...
| _ -> ...)
| U ->
(match c with
| F -> ...
| G -> ...
| _ -> ...)
| _ -> ...
vs.
match a, b, c with
| X, _, _ -> ...
| Y, Z, _ -> ...
| Y, W, _ -> ...
| Y, _, _ -> ...
| U, _, F -> ...
| U, _, G -> ...
| U, _, _ -> ...
| _, _, _ -> ...
I'm trying to understand the following code to declare a function:
let string_of_int = function
| 0 -> "zero"
| 1 -> "one"
| 2 -> "two"
| _ -> "many"
which is the same as
let string_of_int2 x = match x with
|0 -> "zero"
|1 -> "one"
| 2-> "two"
_ -> "many
I understand The second way of declaring the function with is trying to match the input x with several possibilities that it could be. But I don't understand the first way to do it. What does function keyword do?
Also,
what does 'a'..'z' do in the following code?
let is_capital = function
| 'a'..'z' -> false
| 'A'..'Z' -> true
|_ -> failwith "Not a valid letter"
Why can't I have a function like this:
let examplefunc = function
|"string"-> Printf.printf "a string"
|3 -> Printf.print "an integer"
|true-> Printf.printf "a boolean"
|- -> Printf.printf "whatever"
The function keyword is a variant of fun that takes in account that the behavior of the function often directly depends on the value of the argument. For instance, if we start with the following definition of the factorial function:
For a positive integer n, n! is 1 if n = 0, and n * (n-1)! otherwise
then the natural translation to OCaml is
let factorial = function
| 0 (* if n = 0 *) -> 1
| n (* otherwise *) -> n * factorial (n-1)
like you said this strictly equivalent to
let factorial = fun n -> match n with
| 0 (* if n = 0 *) -> 1
| n (* otherwise *) -> n * factorial (n-1)
but when the argument of the function is immediately deconstructed in a pattern matching, it may be more readable to use function directly.
Concerning '0'..'9', those are range pattern that matches all characters (i.e '0'|'1'|'2'|'3'|'4'|..| '9' between the lower and upper bounds (included) of the range (following the ascii ordering of characters)
let is_digit = function '0'..'9' -> true | _ -> false
is_digit '0' (* returns true *);;
is_digit 'a' (* returns false *);;
I am trying to write a function run taking a parameter to parametrize its level of execution. I want this function to return its output after a given level. I used GADTs to have the output of run depends on its input.
Here is the code:
type _ level_output =
| FirstO : int -> int level_output
| SecondO : float -> float level_output
| ThirdO : string -> string level_output
type _ run_level_g =
| First : int run_level_g
| Second : float run_level_g
| Third : string run_level_g
type run_level = Any : 'a run_level_g -> run_level
let first _ =
(*do stuff*)
1
let second _ =
(*do stuff*)
2.5
let third _ =
(*do stuff*)
"third"
let run1 (type a) (level:a run_level_g) data : a level_output =
let out = first data in
match level with
| First -> FirstO out
| Second ->
let out = second out in
SecondO out
| Third ->
let out = second out in
let out = third out in
ThirdO out
let run2 (type a) (level:a run_level_g) data : a level_output =
let out = first data in
if Any level = Any First
then FirstO out
else
let out = second out in
if Any level = Any Second
then SecondO out
else
let out = third out in
ThirdO out
type (_,_) eq = Eq : ('a,'a) eq
let eq_level (type a b) (x:a run_level_g) (y:b run_level_g) : (a, b) eq option =
match x, y with
| First, First -> Some Eq
| Second, Second -> Some Eq
| Third, Third -> Some Eq
| _ -> None
let cast_output (type a b) (Eq:(a, b) eq) (v:a level_output) : b level_output = v
let run3 (type a) (level:a run_level_g) data : a level_output =
let out = first data in
let eq = eq_level First level in
match eq with
| Some eq -> cast_output eq (FirstO out)
| None ->
let out = second out in
let eq = eq_level Second level in
match eq with
| Some eq -> cast_output eq (SecondO out)
| None ->
let out = third out in
let eq = eq_level Third level in
match eq with
| Some eq -> cast_output eq (ThirdO out)
| None -> failwith "this can't happen"
There are three versions of run. The first one works well but there is code duplication, which I would like to remove. I would like my function to look more like run2 but this one does not compile because the type checker can't infer the type from the if-condition. An answer to that problem is run3 but now I have this clunky failwith case that obviously can't happen.
I was wondering if there was a way for me to have the best of both worlds, a function with no code duplication and no failwith case?
I find your function run1 the most readable one, by far.
One possibility to remove some code duplication may be to make run1 recursive.
First, one can define a short helper function to extract data from level_output
let proj (type a) (x:a level_output): a =
match x with
| FirstO x -> x
| SecondO x -> x
| ThirdO x -> x;;
then a recursive variant of run may be written as
let rec run: type a. a run_level_g -> 'b -> a level_output =
fun level data -> match level with
| First -> FirstO(first data)
| Second -> SecondO(second ## proj ## run First data)
| Third -> ThirdO(third ## proj ## run Second data);;
I'm new to f# and fsUnit and I'm wondering how to test a pattern matching statement using fsUnit. For example, if i have the following code how would you write a fsunit test for it?
let Menu () =
let Choice = Console.ReadLine()
match Choice with
| "A" | "a" -> Function1()
| "B" | "b" -> Function2()
| "C" | "c" -> Function3()
| _ -> Printfn"Error"
First of all, you'd separate the code that implements the matching logic from the code that reads the input, because you can only test that the result of some call is correct:
let handleInput choice =
match choice with
| "A" | "a" -> Function1()
| "B" | "b" -> Function2()
| "C" | "c" -> Function3()
| _ -> "Error"
let menu () =
let choice = Console.ReadLine()
let output = handleInput choice
printfn "%s" output
Now you can write a series of tests that check that the string returned by handleInput is the string that you are expecting for each input:
handleInput "A" |> should equal "whatever Function 1 returns"
handleInput "b" |> should equal "whatever Function 2 returns"
handleInput "D" |> should equal "Error"
I found this code to evaluate expressions in OCaml on the internet and want to try to understand how it works, but when I enter it in my editor and run it I get the following error:
type t =
| Integer of int
| Binary of binary * t * t
and binary =
| Add
| Sub
| Mult
| Div
type token =
| INTEGER of int
| ADD
| SUB
| MULT
| DIV
let rec eval = function
| Integer(k) -> k
| Binary(op, a, b) ->
(match op with
| Add -> ( + )
| Sub -> ( - )
| Mult -> ( * )
| Div -> ( / )) (eval a) (eval b)
let lexer s =
let open Str in
let split s =
let rec splitchar x l =
if x< 0 then l else splitchar (x-1) ( s.[x]:: l ) in
splitchar ( String.length s -1) []
|> List.map
(function
| "+" -> ADD
| "-" -> SUB
| "*" -> MULT
| "/" -> DIV
| _ -> failwith "lexer: Invalid token: %s" );;
Characters 280-282:
| _ -> failwith "lexer: Invalid token: %s" );;
^^
Error: Syntax error
The error message doesn't help very much and I've tried a few changes that only make things worse. Can anyone help me get started by figuring out what the syntax error is?
There is a couple of issues :
split is defined but not used.
failwith expects a string, not a format.
For the first issue : you have to use split before List.map:
...in split s | List.map...
failwith expect a string, in the current case, the mistake is that it is a string that looks more a format string that waits for another string.
The fix is as below :
- first catch the string
- then use it to form the final string expected by failwith
(function
| "+" -> ADD <br>
| "-" -> SUB <br>
| "*" -> MULT <br>
| "/" -> DIV <br>
| _ as s -> failwith ("lexer: Invalid token: " ^ s) );;
But I am not sure at all the whole code will work....