Why is "_" used in active pattern? - f#

From this link I see that they use an "_" in active pattern.
let (|Int|_|) str =
match System.Int32.TryParse(str) with
| (true,int) -> Some(int)
| _ -> None
When I look at an example from a different link I don't see the underscore.
let (|Even|Odd|) input = if input % 2 = 0 then Even else Odd
What is the difference between these two implementations?

This is written on this doc page.
(|Int|_|) str =... is partial Active Patterns. let (|Even|Odd|) input =... is Active Patterns. See below.
// From doc link
module ActivePatternSample =
let (|Even|Odd|) input = if input % 2 = 0 then Even else Odd
let TestNumber input =
match input with
| Even -> printfn "%d is even" input
| Odd -> printfn "%d is odd" input
// Rewrite to partial Active Pattern
module PartialActivePatternSample =
let (|Even|_|) input =
match (input%2) with
| 0 -> Some input
| _ -> None
let (|Odd|_|) input =
match input%2 with
| 1 -> Some input
| _ -> None
let TestNumber input =
match input with
| Even input -> printfn "%A is even" input
| Odd input -> printfn "%A is odd" input
| _ -> printfn "can not come here"

Related

Expression was expected to have a type but here has type String

It's my third time today running and this buzz word functional language F# is driving me mad yet when I get certain bits right it feels good
earlier I had a problem with recursive loop someone suggested a way forward and now I am getting the above error, the problem is I know my type is going to be a string so why is the compiler complaining?
Aim was to put 12 weeks of learning into practice so I wanted to work on basic chat bot so far I can hold a basic level conversation, however, there are few things that are still out of my scope for example
why can't I call my type? IUserError to pass user input and check if they have said something that is not in my subject list then to response back with invalid input.
My other issue is to keep things simple I want to convert all input into lowercase string this is also proven to be a challenge.
and then there is numeric at some stage of the conversation user gets to room location for some reason I can find a way other than to do this check.
there is very few tutorial online and the book I am using does not explain things well. I am pleased with what I have achieved so far
if someone can explain where I am going wrong with this because in C# this would have been gone and dusted.:(
here is my whole code feel free to discuss:
open System
open System.IO
open System.Speech.Synthesis
// required for regular expression
open System.Text.RegularExpressions
// init randomizer
let rand = new Random()
// recursive response function find the first match with a key token
// response back acordingly
// Initialise a new instance of SpeechSynthesizer
let voice (sentence: string) =
use speech = new SpeechSynthesizer(Rate= -3)
//speech.SelectVoice("Microsoft Huihui Desktop")
speech.Speak(sentence)
// define functions of set list campus area
let mpCampusArea = Set.ofList ["Cisco Labs"; "The Bridge"; "Security
Area";
"Mac Labs"; "Open Access"]
//active patterns
//method for checking room number
let chkroom () =
let roomNumbers = seq {
yield 158
yield 123
yield 333 }
printfn "Room not found could it be :"
for items in roomNumbers do
printfn "%A" items
let (|Campuses|None|) users =
if Regex.Match(users,".*(MP?|mp|Curzon|curzon|ParkSide?).*" ).Success
then Campuses
else
None
// Apply Active pattern
let(|Repair|None|) input = // any sentence with broken|break|damaged is
require repair
if Regex.Match(input , ".*(broken?|break|damaged?).*").Success
then Repair
else
None
let (|ParkSide|None|) input =
if Regex.Match(input , ".*(P158|P159|P160).*").Success
then ParkSide
else
None chkroom
let (|RoomLocation|None|) str2 =
if Regex.Match(str2, ".*(158|140|150).*").Success
then RoomLocation
else
None chkroom
// Define an active recognizer for keywords that express salutation.
let (|Bye|Answer|NoSubject|MyGirlFriend|Faulty|None|) input =
match input with
| "goodbye" | "bye" | "go" |"get lost"
-> Bye
| "who" | "how" | "when" |"where"
-> Answer
| "car" |"what" |"name" |"bcu"
-> NoSubject
| "lonely" |"love" | "friendship"
-> MyGirlFriend
| "device" |"software" |"phone"
-> Faulty
| _
-> None
let (|Computer|Other|) input =
match input with
|"goodbye"|"bye"|"go" -> Computer
|_ -> Other
// select possible likely hood response based on random number for hello
subject
// Interact with the user
// Subject faulty software and Hardware
let faulty_response (str:string) =
let x = rand.Next(5)
match x with
| 0 -> "My advice is to restart the software / hardware?"
| 1 -> "My advice is relax it will be sorted."
| 2 -> "My advice is bin your device / software."
| 3 -> "Please throw your software / hardware in the recycle bin"
| 5 -> "Kiss your device / software as this always works for me."
| _ -> ""
let good_bye_response () =
let b = rand.Next(5)
match b with
| 0 -> "Good bye Babe"
| 1 -> "Thank God "
| 2 -> "We have to be positive love BCU"
| 3 -> "Live is beautiful but you are a smelly poo little fella BYE!"
| 4 -> "Good bye and thanks for complainting"
| _ -> ""
let answer_response () =
let x = rand.Next(10)
match x with
| 0 -> "Please go and complait to Waheed Rafiq"
| 1 -> "Please go and see Emmett Cooper"
| 2 -> "So you want me to kick a fuss?"
| 3 -> "What a waste of time"
| 4 -> "Please go and see BCU tech department"
| 5 -> "OMG and so what"
| 6 -> "Jump of the roof it will most likely help us all"
| 7 -> "Let's talk about the toliet shall we"
| 8 -> "why don't you use pattern matching with regular expressions!"
| 9 -> "Speak to the Queen she will mostly likely deals with BCU
complaints"
| _ -> ""
let none_response (str:string) =
let n = rand.Next(10)
match n with
| 0 -> "What would you"+ str + "like to chat about ?"
| 1 -> "I do not understand please ask again !"
| 2 -> "How about you Speak english and I log your helpdesk call yeah?"
| 3 -> "Sorry to hear that. Are you sure you want to complaint ?"
| 4 -> "This is a complaint Chat bot where you log helpdesk calls.
Please Refer to Cortana for her services.!"
| 5 -> "Let just complaint yeah for the sake of complaining ?"
| 6 -> "OKay what is your complaint about ?"
| 7 -> "Are you a human because you certainly do not behave like one!"
| 8 -> "The moon is epic. What is broken ?"
| 9 -> "Do you always complaint? Try logging it like my PC is broken
yeah !"
| _ -> ""
type Day =
| Monday
| Tuesday
| Wednesday
| Thursday
| Friday
| Saturday
| Sunday
let isWeekend x =
match x with
|Saturday |Sunday -> true
|_-> false
// using regular expression to tokenisse line of text
let matchWords = Regex(#"\w+")
let token (text:string) =
text.ToLowerInvariant()
|> matchWords.Matches
// Crossing the stream
type IUserError =
interface
end
type Error = { ErrorMessage:string; ErrorCode:int}
interface IUserError
type Success = { Status:string }
interface IUserError
let error = {ErrorMessage = "Incorrect input please enter a subject
phase";
ErrorCode = 250} :> IUserError
match error with
| :? Error as e -> printfn "Code %i \n Message: %s" e.ErrorCode
e.ErrorMessage
| :? Success -> printfn "Success"
|_ -> failwith "Invalid option"
//printfn "%A" error
//recursive response function
let rec response (token: string) (str: string) =
match token with
| Bye
-> good_bye_response ()
| Answer
-> answer_response ()
| Faulty
-> faulty_response str
| Repair
->
sprintf "%s" "Which Campus is the device in?"
| Campuses
-> sprintf "%s" "Which room is the device in?"
| RoomLocation
-> sprintf "%s" "Your call is log. Do you wish to quit?"
|_ when token.Contains("yes") -> "Okay logging you out"
|_ when token.Contains("no") -> answer_response ()
| NoSubject
-> 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 ""
let rec chat () =
let valueInput = Console.ReadLine()
printf "Helpdesk-BCU Response --> %s \n" (response "" valueInput)
let keepRunning, message = response valueInput
printfn ">> %s" message
if keepRunning then chat()
//let rec chat () =
// if Break = false then
// let valueInput = Console.ReadLine()
// printf "Helpdesk-BCU Response --> %s \n" (response "" valueInput)
// if Break = false then
// chat()
// else
// ChatEnd()
let BCU_response (str: string) =
if (str.IndexOf(" ") > 0) then
response (str.Substring(0,str.IndexOf(" "))) (str.Substring(str.IndexOf("
")+1)) + "\n"
else
response str "" + "\n"
// call back feature for the chatbot
//[<EntryPoint>]
//let main argv = printfn "%A" argv
// Advance expression lamba [ Emmett helps required]
let ifancyHerList =
[
("Sara",1); ("Saima",2); ("Zoe",3); ("Scarlett",4);
("Jennifer",5);("Sandra Bullock",6)
]
let myGirlFriend () =
List.pick (fun funToNight ->
let n = rand.Next(10)
if (snd funToNight) = n
then Some (fst funToNight)
else None
) ifancyHerList
//match myGirlFriend with
//| Some name -> printfn "Your date for tonight is %A lucky fella" name
//| None -> printfn "You don't have a date tonight!"
//
printfn "Welcome to the BCU Complaint Chat Bot"
printf "Please enter your first name -->"
let data = Console.ReadLine()
//let rec complaints n =
// printf "%s what do you want to complain about? -->" data
//complaints()
chat()
printfn "The avaialbe areas at Millennium point are: %A" mpCampusArea
printfn "Which day is Weekend on?"
let x = Console.ReadLine()
0
any helps / pointers / anything as this is driving me nuts
I shall post a link direct to the project file if you wish to download it and have a closer look , much appericate your support.
the link to the project file
I'm not sure using an interface is what you want to do here. You don't have any abstract methods defined for IUserError, but then again maybe you were saving that for later. Also, you have a match with block hanging there with no function.
Here is my interpretation of what you could do:
// Crossing the stream
type Error = { ErrorMessage:string; ErrorCode:int}
type Success = { Status:string }
type UserError =
| Error of Error
| Success of Success
let printResponse (error:UserError) =
match error with
| Error (e) -> printfn "Code %i \n Message: %s" e.ErrorCode e.ErrorMessage
| Success _ -> printfn "Success"
|_ -> failwith "Invalid option"
let error = Error {ErrorMessage = "Incorrect input please enter a subject phase"; ErrorCode = 250}
Using fsi to evaluate printResponse, it should look like this:
> printResponse error;;
Code 250
Message: Incorrect input please enter a subject phase
val it : unit = ()

How to construct a match expression

I am allowing a command-line parameter like this --10GB, where -- and GB are constant, but a number like 1, 10, or 100 could be substituted in between the constant values, like --5GB.
I could easily parse the start and end of the string with substr or written a command line parser, but wanted to use match instead. I am just not sure how to structure the match expression.
let GB1 = cvt_bytes_to_gb(int64(DiskFreeLevels.GB1))
let arg = argv.[0]
let match_head = "--"
let match_tail = "GB"
let parse_min_gb_arg arg =
match arg with
| match_head & match_tail -> cvt_gb_arg_to_int arg
| _ -> volLib.GB1
I get a warning saying _ This rule will never be matched. How should the what is an AND expression be constructed?
You can't match on strings, except matching on the whole value, e.g. match s with | "1" -> 1 | "2" -> 2 ...
Parsing beginning and end would be the most efficient way to do this, there is no need to get clever (this, by the way, is a universally true statement).
But if you really want to use pattern matching, it is definitely possible to do, but you'll have to make yourself some custom matchers (also known as "active patterns").
First, make a custom matcher that would parse out the "middle" part of the string surrounded by prefix and suffix:
let (|StrBetween|_|) starts ends (str: string) =
if str.StartsWith starts && str.EndsWith ends then
Some (str.Substring(starts.Length, str.Length - ends.Length - starts.Length))
else
None
Usage:
let x = match "abcd" with
| StrBetween "a" "d" s -> s
| _ -> "nope"
// x = "bc"
Then make a custom matcher that would parse out an integer:
let (|Int|_|) (s: string) =
match System.Int32.TryParse s with
| true, i -> Some i
| _ -> None
Usage:
let x = match "15" with
| Int i -> i
| _ -> 0
// x = 15
Now, combine the two:
let x = match "--10GB" with
| StrBetween "--" "GB" (Int i) -> i
| _ -> volLib.GB1
// x = 10
This ability of patterns to combine and nest is their primary power: you get to build a complicated pattern out of small, easily understandable pieces, and have the compiler match it to the input. That's basically why it's called "pattern matching". :-)
The best I can come up with is using a partial active pattern:
let (|GbFormat|_|) (x:string) =
let prefix = "--"
let suffix = "GB"
if x.StartsWith(prefix) && x.EndsWith(suffix) then
let len = x.Length - prefix.Length - suffix.Length
Some(x.Substring(prefix.Length, len))
else
None
let parse_min_gb_arg arg =
match arg with
| GbFormat gb -> gb
| _ -> volLib.GB1
parse_min_gb_arg "--42GB"

Pattern matching numeric strings

I have a function that pattern matches its argument, which is a string:
let processLexime lexime
match lexime with
| "abc" -> ...
| "bar" -> ...
| "cat" -> ...
| _ -> ...
This works as expected. However, I'm now trying to extend this by expressing "match a string containing only the following characters". In my specific example, I want anything containing only digits to be matched.
My question is, how can I express this in F#? I'd prefer to do this without any libraries such as FParsec, since I'm mainly doing this for learning purposes.
You can use active patterns: https://msdn.microsoft.com/en-us/library/dd233248.aspx
let (|Integer|_|) (str: string) =
let mutable intvalue = 0
if System.Int32.TryParse(str, &intvalue) then Some(intvalue)
else None
let parseNumeric str =
match str with
| Integer i -> printfn "%d : Integer" i
| _ -> printfn "%s : Not matched." str
One way would be an active pattern
let (|Digits|_|) (s:string) =
s.ToCharArray() |> Array.forall (fun c -> System.Char.IsDigit(c)) |> function |true -> Some(s) |false -> None
then you can do
match "1" with
|Digits(t) -> printf "matched"
I would use regular expressions combined with active patterns. With regular expressions you can easily match digits with \d and active patterns makes the syntax nice inside your match.
open System.Text.RegularExpressions
let (|ParseRegex|_|) regex str =
let m = Regex("^"+regex+"$").Match(str)
if (m.Success) then Some true else None
let Printmatch s =
match s with
| ParseRegex "w+" d -> printfn "only w"
| ParseRegex "(w+|s+)+" d -> printfn "only w and s"
| ParseRegex "\d+" d -> printfn "only digis"
|_ -> printfn "wrong"
[<EntryPoint>]
let main argv =
Printmatch "www"
Printmatch "ssswwswwws"
Printmatch "134554"
Printmatch "1dwd3ddwwd"
0
which prints
only w
only w and s
only digis
wrong

Match a number if it is multiple of 2

I'm learning f# and currently I'm with the match keyword. I'm modifying the next example, to print into the screen if a numbers is multiple of 2, it's mod is 0.
[<Literal>]
let Three = 3
let filter123 x =
match x with
// The following line contains literal patterns combined with an OR pattern.
| 1 | 2 | Three -> printfn "Found 1, 2, or 3!"
// The following line contains a variable pattern.
| var1 -> printfn "%d" var1
for x in 1..10 do filter123 x
I have modified it and coded an additional match for:
| x % 2 == 0 -> printfn "it's multiple of 2!"
But that doesn't work, it says that "%" it's an undefined symbol... any ideas? Thanks!
This is a classic Tim Toady. The other answers are perfectly correct. I would add a couple of variations:
// Eugene's answer
let filterEven1 x =
match x with
| _ when x % 2 = 0 -> printfn "%d is even!" x
| _ -> printfn "%d is not even" x
// equivalent to above, but with "function" match syntax
let filterEven2 = function
| x when x % 2 = 0 -> printfn "%d is even!" x
| x -> printfn "%d is not even" x
// variation on Gene's answer
let (|Even|Odd|) x =
if x % 2 = 0 then Even(x) else Odd(x)
let filterEven3 = function
| Even(x) -> printfn "%d is even!" x
| Odd(x) -> printfn "%d is not even" x
// probably how I would do it
let filterEven4 x =
match x % 2 with
| 0 -> printfn "%d is even!" x
| _ -> printfn "%d is not even" x
You cannot use an expression as a match case. Another alternative to a guarded pattern would be defining an active pattern:
let(|Even|Odd|) (x:int) =
if x % 2 = 0 then Even else Odd
and then using it as a normal pattern case
.......
| Even -> printfn "it's multiple of 2!"
.......
You need to use guarded pattern rule:
| _ when x % 2 = 0 -> printfn "it's multiple of 2!"

Literal Attribute not working

After reading Chris' answer to F# - public literal and the blog post at http://blogs.msdn.com/b/chrsmith/archive/2008/10/03/f-zen-the-literal-attribute.aspx I don't get why the following is not working:
[<Literal>]
let one = 1
[<Literal>]
let two = 2
let trymatch x =
match x with
| one -> printfn "%A" one
| two -> printfn "%A" two
| _ -> printfn "none"
trymatch 3
This keeps printing "3", although I think it shouldn't. What is it that I don't see here?
I think that literals need to be Uppercase. The following works fine:
[<Literal>]
let One = 1
[<Literal>]
let Two = 2
let trymatch x =
match x with
| One -> printfn "%A" One
| Two -> printfn "%A" Two
| _ -> printfn "none"
trymatch 3
In addition, if you want a nice general solution for this without using literals, you can define a parameterized active pattern like this:
let (|Equals|_|) expected actual =
if actual = expected then Some() else None
And then just write
let one = 1
let two = 2
let trymatch x =
match x with
| Equals one -> printfn "%A" one
| Equals two -> printfn "%A" two
| _ -> printfn "none"
The other answers are right - you must start your identifier with an uppercase letter. See section 7.1.2 of the spec (Named Patterns), which states that:
If long-ident is a single identifier that does not begin with an uppercase character then it is always interpreted as a variable-binding pattern and represents a variable that is bound by the pattern
Also if you don't want to have Uppercase literals you can put them in a module (here named Const):
module Const =
[<Literal>]
let one = 1
[<Literal>]
let two = 2
let trymatch x =
match x with
| Const.one -> printfn "%A" Const.one
| Const.two -> printfn "%A" Const.two
| _ -> printfn "none"
trymatch 3
Don't ask me why, but it works when you write your literals uppercase:
[<Literal>]
let One = 1
[<Literal>]
let Two = 2
let trymatch (x:int) =
match x with
| One -> printfn "%A" One
| Two -> printfn "%A" Two
| _ -> printfn "none"
trymatch 3

Resources