let IntAndString value =
let (|Match|_|) pattern input =
let m = Regex.Match(input, pattern) in
if m.Success then Some ([ for g in m.Groups -> g.Value ]) else None
match value with
| Match "(\d+)(\w+)" x -> x
| Match "(\w+)" x -> x
| Match "(\d+)" x -> x + "MY VALUE"
| _ -> List.Empty
how can I add a string to my string list here ?
You can append to a list with the # operator. This operator concatenates two lists together, so you'll have to wrap the element you want to append in its own list like this:
| Match "(\d+)" x -> x # ["MY VALUE"]
You could also use the list constructor, ::. If prepending instead of appending is OK:
| Match "(d\+)" x -> "MY VALUE" :: x
Related
When I run the code below I get an error. I am using Map.TryFind and its not working. In console, I get a red line under familyinc.TryFind(tract) and the error below.
let data =
seq { for (state,work) in statecsv do
let (family,income) = familyinc.TryFind(state)
let fam =
match fam with
| Some x -> x
| None -> "Not a Record"
let inc =
match inc with
| Some x -> x
| None -> "Not an income"
yield (state,work,inc,fam)
}
The ERROR:
error FS0001: This expression was expected to have type
''a * 'b'
but here has type
'(string * decimal) option'
Answer to the edited question: The problem is the same as in the previous one, you are pattern matching on a tuple while you are binding an option. You should do something like this instead:
// Bind the whole option
let result = familyinc.TryFind(state)
// Pattern match on it
match result with
| Some (family , income) -> yield (state,work,family,income)
| None -> yield (state,work,"Not a Record","Not an Income")
Of course you could also do match familyinc.TryFind(tract) with, there's no need to bind to variable here.
The issue is you are pattern matching on the result of Map.TryFind() as if it would return a tuple but it actually returns an option as it may fail to find they key you are looking for.
In all FP languages understanding option types and pattern matching is essential. In fact both of these features make FP a superior alternative to OO languages. Using option types you can avoid getting null exceptions, using pattern matching you can deconstruct values. In this case you can filter out non-existing keys, and convert the option result into normal values:
//create test dictionary
let map1 = [("a",1); ("b",2);("c",3)] |> Map.ofList
//list of keys, "d" doesn't exist in the dictionary/map
let keys = ["a";"b";"d"]
keys
|> List.map (fun x -> map1.[x])
//System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
keys
|> List.map (fun x -> map1.TryFind(x))
//You get back a string option list, with the last element missing as the key "d" doesn't exist
//val it : int option list = [Some 1; Some 2; None]
//Method A: filter out the none existing items
keys
|> List.map (fun x -> map1.TryFind(x))
|> List.choose id //choose will get rid of the Nones and return the actual value, not the option. id is the identity function.
//Method B: replace the None with some default value, and also get rid of the option
//Let's say you replace each non existing value with 999
keys
|> List.map (fun x -> map1.TryFind(x))
|> List.map (Option.defaultValue 999)
//val it : int list = [1; 2; 999]
//In general if necessary you can always pattern match
let myOption1 = Some "A"
let myOption2 = None
match myOption1 with
| Some x -> x //try matching whatever is in myOption1 and returns the x portion of Some x, in this case "A"
| None -> "No value"
//val it : string = "A"
match myOption2 with
| Some x -> x
| None -> "No value" //since the value of myOption2 is None, Some x won't match, None will match, and return "No value"
//val it : string = "No value"
I tried to use this code to scramble the characters into different characters and return a new list with those new characters. However, I keep getting errors saying : "a list but here has type char" on line 3, "a list list but given a char list" on the line 13 . Not sure how to fix this. Thanks in advance for the help.
let _scram x =
match x with
| [] -> [] // line 3
| 's' -> 'v'
| 'a' -> 's'
| 'e' -> 'o'
| '_' -> '_'
let rec scramble L P =
match L with
| [] -> P
| hd::t1 -> scramble t1 (P # (_scram hd))
let L =
let p = ['h'; 'e'; 'l'; 'l'; 'o'] //line 13
scramble p []
That's because you are calling the _scram as second operand of the (#) operator which concatenates two lists, so it infers that the whole expression has to be a list.
A quick fix is to enclose it into a list: (P # [_scram hd]), this way _scram hd is inferred to be an element (in this case a char).
Then you will discover your next error, the catch-all wildcard is in quotes, and even if it wouldn't, you can't use it to bind a value to be used later.
So you can change it to | c -> c.
Then your code will be like this:
let _scram x =
match x with
| 's' -> 'v'
| 'a' -> 's'
| 'e' -> 'o'
| c -> c
let rec scramble L P =
match L with
| [] -> P
| hd::t1 -> scramble t1 (P # [_scram hd])
let L =
let p = ['h'; 'e'; 'l'; 'l'; 'o']
scramble p []
F# code is defined sequentially. The first error indicates there is some problem with the code upto that point, the definition of _scram. The line | [] -> [] implies that _scram takes lists to lists. The next line | 's' -> 'v' implies that _scram takes chars to chars. That is incompatible and that explains the error.
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
I've got this function, what I want to do is take a list, split every element in the list on '.' and place the separated elements in 2 different lists, my problem now is I'm getting an error that says the let expression is unfinished and I think it has to do with not having a return value, is there a way to bypass this or am I doing something completely wrong?
let klist = []
let olist = []
let listSplit list =
match list.Split '.' with
| [| x;y |] -> x :: klist, y :: olist
| [| x |] -> x :: klist
| _ -> None;;
It looks like you want something like
let listSplit (list: string list) =
let acc (kl, ol) = function
| [| x; y |] -> (x::kl, y::ol)
| [| x |] -> (x::kl, ol)
list |> List.map (fun s -> s.Split('.'))
|> List.filter(fun a -> a.Length = 1 || a.Length = 2)
|> List.fold acc ([],[])
Your existing code has a few problems:
list has no split method. Strings do have a Split method, so you probably want to split each string in the input list, which you can do with List.map.
Your match expression does not type check, and each branch has a different type - the first returns string list * string list, the second string list and the third a' option.
I'm fairly new to F# and I wanted to compare two values with the (match ... with ...) syntax
The problem arises when I attempt to compare two values like this:
let value1 = 19
let isValue1 y =
match y with
| value1 -> y + 1
| _ -> y
I get a warning that the "| _ -> y" portion of the code will never be reached. Why is this?
I know that I can do the following to get the function to work the way I want it to:
let value1 = 19
let isValue1 y =
match y with
| _ when y = value1 -> true
| _ -> false
This works as well
let value1 = 19
let isValue1 y =
match y with
| 19 -> true
| _ -> false
I'm just curious about why I can't do that, and how match actually works.
The value1 within the match statement is defined as a new variable, the value of which is set to y (as a match). The value1 you define just above is ignored, just as if you were declaring a local variable in a C# function with the same name as a class variable. For this reason, the first match condition will match everything, not just the previously defined value of value1, hence the error. Hope that clarifies matters.
Pattern-matching is both a control construct (what code executes next) and a binding construct (like 'let', bind a name to a value). So when you do
match expr with
| name -> ...
the pattern ("name") always matches and the identifier 'name' just gets bound to the value of the expression. This is why pattern-matching is mostly used with discriminated unions (case types), where you match based on the structure. E.g.
match someOption with
| Some(x) -> ... // binds x
| None -> ...
match someList with
| h :: t -> ... // binds h and t to head/tail
| [] -> ...
You can just match the Input to Literals/Identifiers marked by the [<Literal>] Attribute without binding it.
For Example:
#light
[<Literal>]
let E = 2.718281828459
let isE x =
match x with
| E -> true
| _ -> false
print_any (isE 3.2)
print_any (isE E)
According to Crish Smith