This question already has answers here:
FirstOrDefault In F#
(4 answers)
Closed 9 years ago.
The code below throws a NullReferenceException within the FirstOrDefault() method:
open System
open System.Collections.Generic
open System.Linq
[<EntryPoint>]
let main argv =
let suspects = seq {
yield ("Frank", 1.0)
yield ("Suzie", 0.9)
yield ("John", 0.5)
// yield ("Keyser Soze", 0.3)
}
let likely = suspects.FirstOrDefault(fun (name, confidence) -> name = "Keyser Soze")
printfn "Name: %s" (fst likely)
Console.ReadLine() |> ignore
0
What's the best way to work around that? Catching it seems wrong. I could grab the iterator manually and put it in a while loop, but that's - well, wrong on so many levels.
[Edit]
I can't even do what I would do in C#, namely, check to see if the result is null or default, for two reasons: (1) The error is thrown in the FirstOrDefault() method, not when I reference the result; and (2) if I try to check for null, the compiler complains that `The type '(string * float)' does not have 'null' as a proper value':
if likely = null then
printfn "Nothing to see here"
Any suggestions?
As noted above, Seq.tryFind is the idiomatic way of achieving that. If you really must use FirstOrDefault() you could do something like this:
open System.Collections.Generic
open System.Linq
let suspects = seq {
yield Some("Frank", 1.0)
yield Some("Suzie", 0.9)
yield Some("John", 0.5)
// yield ("Keyser Soze", 0.3)
}
let likely = suspects.FirstOrDefault(fun x -> let name, confidence = x.Value
name = "Keyser Soze")
match likely with
| Some(x) -> printfn "Name: %s" (fst x)
| None -> printfn "Not Found"
You can follow hardcode null checks-polluted C# way if you want to:
...
let likely = suspects.FirstOrDefault(fun x -> x.Equals(null) || (fst x) = "Keyser Soze")
if obj.ReferenceEquals(likely, null) then
printfn "Nothing to print"
else
printfn "Name: %s" (fst x)
...
but this is against the major F# idiom upon avoiding null-checks altogether.
EDIT: It seems the alleged NullReferenceException within FirstOrDefault actively referred in comments simply does not happen! With first line of code above changed back to the original
let likely = suspects.FirstOrDefault(fun (name, confidence) -> name = "Keyser Soze")
the snippet works for the sequence of three first tuples without a problem.
Related
i'm writing a small console application in F#.
[<EntryPoint>]
let main argv =
high_lvl_funcs.print_opt
let opt = Console.ReadLine()
match opt with
| "0" -> printfn "%A" (high_lvl_funcs.calculate_NDL)
| "1" -> printfn ("not implemented yet")
| _ -> printfn "%A is not an option" opt
from module high_lvl_funcs
let print_opt =
let options = [|"NDL"; "Deco"|]
printfn "Enter the number of the option you want"
Array.iteri (fun i x -> printfn "%A: %A" i x) options
let calculate_NDL =
printfn ("enter Depth in m")
let depth = lfuncs.m_to_absolute(float (Console.ReadLine()))
printfn ("enter amount of N2 in gas (assuming o2 is the rest)")
let fn2 = float (Console.ReadLine())
let table = lfuncs.read_table
let tissue = lfuncs.create_initialise_Tissues ATM WATERVAPOUR
lfuncs.calc_NDL depth fn2 table lfuncs.loading_constantpressure tissue 0.0
lfuncs.calc_NDL returns a float
this produces this
Enter the number of the option you want
0: "NDL"
1: "Deco"
enter Depth in m
which means it prints what it's suppose to then jumps straight to high_lvl_funcs.calculate_NDL
I wanted it to produce
Enter the number of the option you want
0: "NDL"
1: "Deco"
then let's assume 0 is entered, and then calculate high_lvl_funcs.calculate_NDL
after some thinking and searching i assume this is because F# wants to assign all values before it starts the rest. Then i thought that i need to declaring a variable without assigning it. but people seem to agree that this is bad in functional programming. From another question: Declaring a variable without assigning
so my question is, is it possible to rewrite the code such that i get the flow i want and avoid declaring variables without assigning them?
You can fix this by making calculate_NDL a function of no arguments, instead of a closure that evaluates to a float:
let calculate_NDL () =
Then call it as a function in your match like this:
match opt with
| "0" -> printfn "%A" (high_lvl_funcs.calculate_NDL())
However I'd suggest refactoring this code so that calculate_NDL takes any necessary inputs as arguments rather than reading them from the console i.e. read the inputs from the console separately and pass them to calculate_NDL.
let calculate_NDL depth fn2 =
let absDepth = lfuncs.m_to_absolute(depth)
let table = lfuncs.read_table
let tissue = lfuncs.create_initialise_Tissues ATM WATERVAPOUR
lfuncs.calc_NDL absDepth fn2 table lfuncs.loading_constantpressure tissue 0.0
It's generally a good idea to write as much code as possible as pure functions that don't rely on I/O (like reading from stdin).
Can somebody help me with article of Tomas Petricek: http://tomasp.net/blog/fsharp-dynamic-lookup.aspx/#dynfslinks?
The problem is that it is severely outdated. I understand that namespaces
open Microsoft.FSharp.Quotations.Typed
open Microsoft.FSharp.Quotations.Raw
are gone. So I removed the openings. But there are still errors. "Typed" is not defined. "RecdGet" is not defined. And I suspect they are not the last. I'm trying to prove to my boss that F# is good to use for database normalization. Dynamic lookup of fields would really helped me to deal with similarly named fields having different prefixes.
There is also post of Tomas on fpish: https://fpish.net/topic/None/57493, which I understand predates the article
Here's a rough equivalent:
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
type DynamicMember<'t,'u> = Expr<'t -> 'u>
let getValueReader (expr:DynamicMember<'recdT, 'fieldT>) =
// Match the quotation representing the symbol
match expr with
| Lambda(v, PropertyGet (Some (Var v'), pi, [])) when v = v' ->
// It represents reading of the F# record field..
// .. get a function that reads the record field using F# reflection
let rdr = Reflection.FSharpValue.PreComputeRecordFieldReader pi
// we're not adding any additional processing, so we just
// simply add type conversion to the correct types & return it
((box >> rdr >> unbox) : 'recdT -> 'fieldT)
| _ ->
// Quotation doesn't represent symbol - this is an error
failwith "Invalid expression - not reading record field!"
type SampleRec = { Str : string; Num : int }
let readStrField = getValueReader <# fun (r : SampleRec) -> r.Str #>
let readNumField = getValueReader <# fun (r : SampleRec) -> r.Num #>
let rc = { Str = "Hello world!"; Num = 42 }
let s, n = readStrField rc, readNumField rc
printfn "Extracted: %s, %d" s n
I'm pretty new to F# so it's hard for me to change my mindset after many years of C#/Java OOP.
I have an event handler MyForm.SelectFile(filePath:String) that opens a dialog and let you select the file to read. Once the file is selected, Parser.LoadFile(filePath:String) is called:
static member LoadFile(filePath:String) =
if not <| ZipFile.IsZipFile(filePath) then
failwith "invalid file specified."
use zipFile = new ZipFile(filePath)
if zipFile.Count <> 2 || zipFile |> Seq.exists(fun x -> x.FileName <> "alpha" && x.FileName <> "beta") then
failwith "invalid file specified."
zipFile |> fun x -> Parser.Parse(x.OpenReader())
I'm always expecting the selected file to be a valid zip archive containing 2 files without extension: "alpha" and "beta".
First, is there a better way to sanitize my input?
My if statements are pretty long and I'm sure F# can provide better solutions, but I really can't figure out.
Second, using failwith is forcing me to handle exceptions in my MyForm.SelectFile(filePath:String) method and I think Options could be a better solution.
I can't figure out how to use them if I need to perform two different and consecutive checks (ZipFile.IsZipFile and content) because in between I have to instantiate a ZipFile.
In C# I would just return null whenever a check fails and then checking the return value against null would let me know whether I need to prompt an error or continue.
Current code:
type Parser with
static member isValidZipFile (zipFile:ZipFile) =
(zipFile.Count = 2) && (zipFile |> Seq.forall(fun x -> (x.FileName = "alpha") || (x.FileName = "beta")))
static member LoadFile(filePath:String) =
if not <| ZipFile.IsZipFile(filePath) then
None
else
use zipFile = new ZipFile(filePath)
if not <| Parser.isValidZipFile(zipFile) then
None
else
Some(seq { for zipEntry in zipFile do yield Parser.Parse(zipEntry.OpenReader()) } |> Seq.toArray)
First, the last line of your function could be a bit more elegant if it was written like:
zipFile.OpenReader() |> Parser.Parse
Second, you're on the right track as far as your thinking about using Option. It's really pretty simple in this case:
static member LoadFile(filePath:String) =
if not <| ZipFile.IsZipFile(filePath) then None else
use zipFile = new ZipFile(filePath)
if zipFile.Count <> 2 || zipFile |> Seq.exists(fun x -> x.FileName <> "alpha" && x.FileName <> "beta") then None else
Some (zipFile.OpenReader() |> Parser.Parse)
That last line could also be written as:
zipFile.OpenReader() |> Parser.Parse |> Some
Now, you mentioned that you don't like the long if statement. Let's turn it into a function! And I usually prefer functions with "positive" names, i.e. an isValidInput function is usually more helpful than an isInvalidInput. So let's make a function that checks if a zipfile is actually valid:
let isValid (z:ZipFile) =
z.Count = 2 && z |> Seq.forAll(fun x -> x.FileName = "alpha" || x.FileName = "beta")
Now your LoadFile function can become:
static member LoadFile(filePath:String) =
if not <| ZipFile.IsZipFile(filePath) then None else
use zipFile = new ZipFile(filePath)
if not <| isValid zipFile then None else
zipFile.OpenReader() |> Parser.Parse |> Some
And that looks pretty easy to read, so we can stop refactoring for now.
This piece of code looks weird. Using Sequence expressions for such a simple piece of code is overkill.
Some(seq { for zipEntry in zipFile do yield Parser.Parse(zipEntry.OpenReader()) } |> Seq.toArray)
You could write it better like this
zipFile |> Seq.map (fun ze -> ze.OpenReader () |> Parser.parse) |> Some
Or if you insist in doing it in an array (why?)
zipFile |> Seq.map (fun ze -> ze.OpenReader () |> Parser.parse) |> Seq.toArray |> Some
You'll end up with type signature option<seq<value>>. I am not sure if this is a good idea, but it is not possible to tell without looking at the rest of your code.
If I have a type named Person, and list of functions, for example...
let checks = [checkAge; checkWeight; checkHeight]
...where each function is of the type (Person -> bool), and I want to do the equivalent of...
checkAge >> checkWeight >> checkHeight
...but I don't know in advance what functions are in the list, how would I do it?
I tried the following...
checks |> List.reduce (>>)
...but this gives the following error...
error FS0001: Type mismatch. Expecting a
(Person -> bool) -> (Person -> bool) -> Person -> bool
but given a
(Person -> bool) -> (bool -> 'a) -> Person -> 'a
The type 'Person' does not match the type 'bool'
What am I doing wrong?
It looks like Railway oriented programming would be a good fit here.
If you choose to go this route, you basically have two options.
You can either go all in, or the quick route.
Quick route
You rewrite your validation functions to take a Person option instead of just plain Person.
let validAge (record:Record option) =
match record with
| Some rec when rec.Age < 65 && rec.Age > 18 -> record
| None -> None
Now you should be able to easily chain your function.
checks |> List.reduce (>>)
All in
Alternatively, if you are lazy and don't want to match .. with in every validation function, you can write some more code.
(samples taken from [1])
First there's a bit of setup to do.
We'll define a special return type, so we can get meaningful error messages.
type Result<'TSuccess,'TFailure> =
| Success of 'TSuccess
| Failure of 'TFailure
A bind function, to bind the validations together
let bind switchFunction =
function
| Success s -> switchFunction s
| Failure f -> Failure f
You'll have to rewrite your validation functions as well.
let validAge (record:Record) =
if record.Age < 65 && record.Age > 18 then Success input
else Failure "Not the right age bracket"
Now combine with
checks |> List.reduce (fun acc elem -> acc >> bind elem)
Either way, check out the original article.
There's much more there you might be able to use :)
Edit: I just noticed that I was too slow in writing this answer once again.
Besides, I think Helge explained the concetp better than I did as well.
You may somehow have stumbled upon a dreaded concept. Apperently its the Voldemort (dont say his name!) of functional programming.
With no further ado lets walk right into the code:
type Person =
{ Name : string
Age : int
Weight : int
Height : int }
type Result =
| Ok of Person
| Fail
let bind f m =
match m with
| Ok p -> f p
| _ -> Fail
let (>=>) f1 f2 = f1 >> (bind f2)
let checkAge p =
if p.Age > 18 then Ok(p)
else Fail
let checkWeight p =
if p.Weight < 80 then Ok(p)
else Fail
let checkHeight p =
if p.Height > 150 then Ok(p)
else Fail
let checks = [ checkAge; checkWeight; checkHeight ]
let allcheckfunc = checks |> List.reduce (>=>)
let combinedChecks =
checkAge
>=> checkWeight
>=> checkHeight
let p1 =
{ Name = "p1"
Age = 10
Weight = 20
Height = 110 }
let p2 =
{ Name = "p2"
Age = 19
Weight = 65
Height = 180 }
allcheckfunc p1
combinedChecks p1
allcheckfunc p2
combineChecks p2
At this point I could throw around a lot of weirdo lingo (not really true, I couldnt...), but lets just look at what I have done.
I dropped your return value of bool and went for another type (Result) with either (mark that keyword!) Ok or Fail.
Then made a helper (bind) to wrap and unwrapp stuff from that Result-type.
And a new operator (>=>) to combine the stuff in reduce.
Mind that the first check-function to Fail will shortcut the entire chain and more or less immediately (not calling the other functions) return Fail. In addition you will not know where in this chain it did Fail or which functions ahead of any Fail did actually Ok.
There are methods to also accumulate the errors as you go along, so that you get get a feedback of type: "the checkAge returned Fail, but the others was great success"
The code is mostly stolen from here: http://fsharpforfunandprofit.com/posts/recipe-part2/
And you may want to read about the entire website of Wlaschin and even a lot more to get into the finer and harder details if wanted.
Good luck on your journey to the upper floors of the Ivory Tower. ;-)
Footnote: This is called an Either-monad usually. Its not entirely finished and what not in the above code, but never mind... I think it will work in your case...
The >> operator is useful if you have functions that perform some transformation. For example, if you had a list of functions Person -> Person that turn one person into another.
In your case, it seems that you have functions Person -> bool and you want to build a composed function that returns true if all functions return true.
Using List.reduce you can write:
checks|> List.reduce (fun f g -> (fun p -> f p && g p))
Perhaps an easier option is to just write a function that takes a person and uses List.forall:
let checkAll checks person = checks |> List.forall (fun f -> f person)
There is any way to do it like C/C#?
For example (C# style)
for (int i = 0; i < 100; i++)
{
if (i == 66)
break;
}
The short answer is no. You would generally use some higher-order function to express the same functionality. There is a number of functions that let you do this, corresponding to different patterns (so if you describe what exactly you need, someone might give you a better answer).
For example, tryFind function returns the first value from a sequence for which a given predicate returns true, which lets you write something like this:
seq { 0 .. 100 } |> Seq.tryFind (fun i ->
printfn "%d" i
i=66)
In practice, this is the best way to go if you are expressing some high-level logic and there is a corresponding function. If you really need to express something like break, you can use a recursive function:
let rec loop n =
if n < 66 then
printfn "%d" n
loop (n + 1)
loop 0
A more exotic option (that is not as efficient, but may be nice for DSLs) is that you can define a computation expression that lets you write break and continue. Here is an example, but as I said, this is not as efficient.
This is really ugly, but in my case it worked.
let mutable Break = false
while not Break do
//doStuff
if breakCondition then
Break <- true
done
This is useful for do-while loops, because it guarantees that the loop is executed at least once.
I hope there's a more elegant solution. I don't like the recursive one, because I'm afraid of stack overflows. :-(
You have to change it to a while loop.
let (i, ans) = (ref 0, ref -1)
while(!i < 100 and !ans < 0) do
if !i = 66 then
ans := !i
ans
(This breaks when i gets to 66--but yes the syntax is quite different, another variable is introduced, etc.)
seq {
for i = 0 to 99 do
if i = 66 then yield ()
}
|> Seq.tryItem 0
|> ignore
Try this:
exception BreakException
try
for i = 0 to 99 do
if i = 66 then
raise BreakException
with BreakException -> ()
I know that some folks don't like to use exceptions. But it has merits.
You don't have to think about complicated recursive function. Of
cause you can do that, but sometimes it is unnecessarily bothersome
and using exception is simpler.
This method allows you to break at halfway of the loop body. (Break "flag" method is simple too but it only allows to break at the end of the loop body.)
You can easily escape from nested loop.
For these kind of problems you could use a recursive function.
let rec IfEqualsNumber start finish num =
if start = finish then false
elif
start = num then true
else
let start2 = start + 1
IfEqualsNumber start2 finish num
Recently I tried to solve a similar situation:
A list of, say, 10 pieces of data. Each of them must be queried against a Restful server, then get a result for each.
let lst = [4;6;1;8]
The problem:
If there is a failed API call (e.g. network issue), there is no point making further calls as we need all the 10 results available. The entire process should stop ASAP when an API call fails.
The naive approach: use List.map()
lst |> List.map (fun x ->
try
use sqlComd = ...
sqlComd.Parameters.Add("#Id", SqlDbType.BigInt).Value <- x
sqlComd.ExecuteScala() |> Some
with
| :? System.Data.SqlClient.SqlException as ex -> None
)
But as said, it's not optimal. When a failed API occurs, the remaining items keep being processed. They do something that is ignored at the end anyway.
The hacky approach: use List.tryFindIndex()
Unlike map(), we must store the results somewhere in the lamda function. A reasonable choice is to use mutable list. So when tryFindIndex() returns None, we know that everything was ok and can start making use of the mutable list.
val myList: List<string>
let res = lst |> List.tryFindIndex (fun x ->
try
use sqlComd = ...
sqlComd.Parameters.Add("#Id", SqlDbType.BigInt).Value <- x
myList.Add(sqlComd.ExecuteScala())
false
with
|:? System.Data.SqlClient.SqlException as ex -> true
)
match res with
| Some _ -> printfn "Something went wrong"
| None -> printfn "Here is the 10 results..."
The idiomatic approach: use recursion
Not very idiomatic as it uses Exception to stop the operation.
exception MyException of string
let makeCall lstLocal =
match lstLocal with
| [] -> []
| head::tail ->
try
use sqlComd = ...
sqlComd.Parameters.Add("#Id", SqlDbType.BigInt).Value <- x
let temp = sqlComd.ExecuteScala()
temp :: makeCall (tail)
with
|:? System.Data.SqlClient.SqlException as ex -> raise MyException ex.Message
try
let res = makeCall lst
printfn "Here is the 10 results..."
with
| :? MyException -> printfn "Something went wrong"
The old-fashion imperative approach: while... do
This still involves mutable list.