I'm trying to create a function that converts a string to a bool.
This is what I have for now
let iscomb=
Table.parseTable table
|>> fun row -> row.["IsComb"] |> Models.Bool //returns true or false from a table cell
let Bool (s:string) =
match (s) with
| "true" -> true
| "false" -> false
| _-> sprintf "Error: returns %s" s
This return the type bool does not match the type string
So what I have understod is that we cannot mix different types in a match.
Any suggestion on what I could do?
Thanks in advace.
Just for fun, I thought I would demonstrate using Active Patterns for this. Only really worthwhile if you are checking this often and wanting to do different things based on that and you want to expand what is accepted beyond "true" / "false". It also can remove typo errors like "fasle".
First, we create 2 partial Active Patterns that just cleanup checking for Int32 and bool from string.
Note: You could just use the Bool AP below and stop there.
// Partial active pattern that matches on Int32
let (|Int|_|) (value:string) =
match (System.Int32.TryParse(value)) with
| (true, i) -> Some i
| (false,_) -> None
// Partial active pattern that matches on Bool
let (|Bool|_|) (value:string) =
match (System.Boolean.TryParse(value)) with
| (true,b) -> Some b
| _ -> None
Next, we use those 2 partial Active Patterns to cleanly test our string in an active pattern with 2 choices.
// Active pattern that buckets a string into True or False (or throws)
let(|True|False|) (value:string) =
match value with
| null -> False
| Int i when i > 0 -> True
| Int i when i <= 0 -> False
| Bool true -> True
| Bool false -> False
| _ -> failwithf "Cannot convert %s to bool." value
So how would we use this? Here is a test function where we use the Active Pattern to test a few results.
// quick little function to test a string
let test s =
match s with
| True -> printfn "The value %s is true" s
| False -> printfn "The value %s is false" s
Resulting in the following:
// testing
test "true" // The value true is true
test "TRUE" // The value TRUE is true
test "false" // The value false is false
test "False" // The value False is false
test "-1" // The value -1 is false
test "42" // The value 42 is true
test null // The value is false
test "abc" // System.Exception: Cannot convert abc to bool.
For more info:
FSharp for fun and Profit
F# Online meetup talk
You could replace sprintf for failwith, throwing an exception:
let Bool s =
match s with
| "true" -> true
| "false" -> false
| _-> failwith("Error: returns " + s)
Related
I am trying to better understand how active pattern works - please correct me if i am reading active pattern wrong, taking below example:
let (|UpperCase|) (x:string) = x.ToUpper()
let result = match "foo" with
| UpperCase "FOO" -> true
| _ -> false
I see we are comparing
(Uppercase "foo") with "FOO"
but it looks odd in this case, when i read
| UpperCase "Foo"
shouldn't this code be written like
let result = match UpperCase "foo" with
Is there a better way to read?
In your example, you are combining two patterns: the single case active recognizer without arguments UpperCase with the constant pattern "FOO". The effect is indeed the same as if you were to apply the function (|UpperCase|) inside the match expression:
match "foo" with
| UpperCase "FOO" -> true
| _ -> false
// val it : bool = true
match (|UpperCase|) "foo" with
| "FOO" -> true
| _ -> false
// val it : bool = true
Now, matching constants against constants is not very versatile, so let's make a function instead.
let isFooBarCaseInsensitive = function
| UpperCase "FOO" | UpperCase "BAR" -> true
| _ -> false
// val isFooBarCaseInsensitive : _arg1:string -> bool
isFooBarCaseInsensitive "foo"
// val it : bool = true
isFooBarCaseInsensitive "fred"
// val it : bool = false
Patterns are employed not only with the match and function keywords, but also with try...with, fun, and most notably let:
let (UpperCase foo) = "foo"
// val foo : string = "FOO"
Think of a match as a simplified if/else chain. For example:
match "foo" with
| "foo" -> true
| _ -> false
Could be:
if "foo" = "foo" then true
else false
Active Patterns are implicit function calls. In your example:
match "foo" with
| UpperCase "FOO" -> true
| _ -> false
Is essentially:
if (UpperCase "foo") = "FOO" then true
else false
You're matching the result of pushing "foo" through the call, you just don't have to specify it with the usual function call syntax.
To answer your other question, in this particular case you could very well do this for the same effect:
let UpperCase (x:string) = x.ToUpper()
match UpperCase "foo" with
| "FOO" -> true
| _ -> false
It becomes a little more difficult to do that when you could have multiple pattern results that you'd like to match against, which is where Active Patterns are more useful.
For example:
let (|IsInt|IsString|) (x:obj) = match x with :? int -> IsInt | _ -> IsString
match someValue with
| IsInt -> true
| IsString -> false
I have a situation in finding a sequence of strings that have patterns like XXXX or CCCC or "IIII". I have tried the following code, but it does not work
let rec checkSequence roman=
let r=List.ofSeq roman
match r with
| [] -> true
| a::b::c::d::tail when (a="I" || a="X" || a="C") && a=b && a=c && a=d -> false
| head::tail -> checkSequence tail
checkSequence "CCC"
The error is: This expression was expected to have type string list but here has type string
1-How can I resolve this error?
2-Is there any simpler way to find this patterns?
If you need use a recursion on list you may do something like this:
let checkSequenceStr str =
let rec checkSequence roman =
match roman with
| [] -> true
| 'I'::'I'::'I'::'I'::tail -> false
| 'X'::'X'::'X'::'X'::tail -> false
| 'C'::'C'::'C'::'C'::tail -> false
| head::tail -> checkSequence tail
checkSequence (str |> List.ofSeq)
Or you could use .NET string methods to check patterns directly (which is easier):
let checkPattern (str : string) =
["IIII";"CCCC";"XXXX"] |> List.exists str.Contains |> not
You are using List.ofSeq, this will type force the roman parameter to be of an type list.
https://msdn.microsoft.com/en-us/library/ee340325.aspx
Therefor your error This expression was expected to have type string list but here has type string is due to calling the function wrongly, then an logical error. Therefor change:
checkSequence "CCC"
Into:
checkSequence ["C"; "C";"C"]
I have the following code. For the last two match, the first period has type of DateTime option and the second one has type of int. Why the second one doesn't have option?
let (|Integer|_|) (str: string) =
let mutable intvalue = 0
if Int32.TryParse(str, &intvalue) then Some(intvalue)
else None
let (|DateyyMM|) (str: string) =
let mutable date = new DateTime()
if DateTime.TryParseExact(str,
"yyyyMM",
Globalization.DateTimeFormatInfo.InvariantInfo,
Globalization.DateTimeStyles.None,
&date)
then Some(date)
else None
let (|ParseRegex|_|) regex str =
let m = Regex(regex).Match(str)
if m.Success
then Some (List.tail [ for x in m.Groups -> x.Value ])
else None
.....
match url with
| ParseRegex "....." [DateyyMM period] -> //period type is DateTime option
......
match downloadLink.Url with
| ParseRegex "....." [name; Integer period] -> // period type is int
......
The second case has no option because you added _| at the end of the declaration.
This is setup to allow for a shorthand in a match - so that rather than
match x with
|Some_long_function(Some(res)) -> ...
|Some_long_function(None) -> ...
you can just do
match x with
|Some_long_function(res) -> ...
|_ -> ...
See the MSDN page on active patterns for more: http://msdn.microsoft.com/en-us/library/dd233248.aspx (in particular the secion on partial patterns)
I am trying to match the beginning of strings in f#. Not sure if I have to treat them as a list of characters or what. Any suggestions would be appreciated.
Here is a psuedo code version of what I am trying to do
let text = "The brown fox.."
match text with
| "The"::_ -> true
| "If"::_ -> true
| _ -> false
So, I want to look at the beginning of the string and match. Note I am not matching on a list of strings just wrote the above as an idea of the essence of what I am trying to do.
Parameterized active patterns to the rescue!
let (|Prefix|_|) (p:string) (s:string) =
if s.StartsWith(p) then
Some(s.Substring(p.Length))
else
None
match "Hello world" with
| Prefix "The" rest -> printfn "Started with 'The', rest is %s" rest
| Prefix "Hello" rest -> printfn "Started with 'Hello', rest is %s" rest
| _ -> printfn "neither"
You could also use a guard on the pattern:
match text with
| txt when txt.StartsWith("The") -> true
| txt when txt.StartsWith("If") -> true
| _ -> false
Yes you have to treat them as a list of characters if you want to use a match expression.
Simply transform the string with:
let text = "The brown fox.." |> Seq.toList
Then you can use a match expression but you will have to use chars (the type of elements in the list) for each letter:
match text with
| 'T'::'h'::'e'::_ -> true
| 'I'::'f'::_ -> true
| _ -> false
As Brian suggest Parameterized Active Patterns are much nicer, there a some useful patterns here (go the end of the page).
What would be the most effective way to express the following code?
match cond.EvalBool() with
| true ->
match body.Eval() with
| :? ControlFlowModifier as e ->
match e with
| Break(scope) -> e :> obj //Break is a DU element of ControlFlowModifier
| _ -> next() //other members of CFM should call next()
| _ -> next() //all other values should call next()
| false -> null
cond.EvalBool returns a boolean result where false should return null
and true should either run the entire block again (its wrapped in a func called next)
or if the special value of break is found, then the loop should exit and return the break value.
Is there any way to compress that block of code to something smaller?
I think that the code that you have written is fine. Here's an alternative which I marginally prefer:
let isBreak = function | Break(_) -> true | _ -> false
if cond.EvalBool() then
match body.Eval() with
| :? ControlFlowModifier as e when isBreak e -> e :> obj
| _ -> next()
else
null
I want to point out that it appears there's a subtype hierarchy for the result type of Eval, and if instead that were also a DU, then you could do something like
match body.Eval() with
| ControlFlowModifier(Break e) -> box e
| _ -> next()
Hurray for nested patterns.
I'm not too fond of matching booleans instead of using if-else. What about
let isBreak = function Break _ -> true | _ -> false
...
if cond.EvalBool() then
match body.Eval() with
| :? ControlFlowModifier as e when isBreak e -> box e
| _ -> next()
else null
Or, if you think that special isBreak function shouldn't be necessary (I'd understand that), lets try creating a more general function: C#'s as operator
let tryCast<'T> (o : obj) =
match o with
| :? 'T as x -> Some x
| _ -> None
...
if cond.EvalBool() then
match body.Eval() |> tryCast with
| Some (Break _ as e) -> box e //Break is a DU element of ControlFlowModifier
| _ -> next() //all other values should call next()
else null
I ended up creating an active pattern for this.
Similar logic exist elsewhere so I could make it reusable
let rec next() : obj =
if cond.EvalBool() then
match body.Eval() with
| IsBreak(res) -> res
| _ -> step.Eval() |> ignore ; next()
else null
Looks decent?
To flatten the nested match constructs, you'll need to use nested patterns. This works best for discriminated unions (as pointed out by Brian - and I agree that designing F# code to use primarily discriminated unions is the best thing you can do).
Otherwise, you'll need some active patterns if you want to write the code succinctly using match (ssp posted one example, which shows active patterns specifically for your problem). However, you can do this using the following two reusable active patterns:
let (|TryCast|_|) a : 'res option =
match (box a) with
| :? 'res as r -> Some(r)
| _ -> None
let (|Value|) (l:Lazy<_>) = l.Value
The first one is like :?, but it allows you to nest other patterns to match the value (which isn't possible with as). The second one forces evaluation of lazy value (I suppose that both of them could be declared in F# libraries as they are quite useful). Now you can write:
match lazy cond.EvalBool(), lazy body.Eval() with
| Value(true), Value(TryCast((Break(scope) : ControlFlowModifier)) as e) ->
e :> obj //Break is a DU element of ControlFlowModifier
| Value(true), _ ->
next() //all other values should call next()
| _, _ -> null
EDIT: As Roger pointed out in a comment, this version of the code may not be very readable. I think a better option would be to use only TryCast and format your original code slightly differently (although this isn't completely standard indentation, it is correct and F# compiler handles it fine):
match cond.EvalBool() with
| false -> null
| true ->
match body.Eval() with
| TryCast(Break(scope) as e) -> e :> obj
| _ -> next()
This is probably the most readable option based on pattern matching, but you could also use if instad of the first match as in the version by kvb and combine it with TryCast (this really depends on personal preferences):
if cond.EvalBool() then
match body.Eval() with
| TryCast(Break(scope) as e) -> e :> obj
| _ -> next()
else null
In any case, I believe that TryCast makes the code more readable as you avoid one nesting (which is othervise required because of :? .. as ..).
In case you mean "most effective way" as shortest code, i vote to AP too:
let (|CondEval|_|) (c,_) = if c.EvalBool() then Some true else None
let (|BodyEval|_|) (_,b) =
match b.Eval() with
| ControlFlowModifier as e -> Some e
| _ -> None
match cond,body with
| CondEval _ & BodyEval e -> e :> obj
| true -> next()
| false -> null