I wrote the following code to execute a SQLServer StoredProc in F#
module SqlUtility =
open System
open System.Data
open System.Data.SqlClient
SqlUtility.GetSqlConnection "MyDB"
|> Option.bind (fun con -> SqlUtility.GetSqlCommand "dbo.usp_MyStordProc" con)
|> Option.bind (fun cmd ->
let param1 = new SqlParameter("#User", SqlDbType.NVarChar, 50)
param1.Value <- user
cmd.Parameters.Add(param1) |> ignore
let param2 = new SqlParameter("#PolicyName", SqlDbType.NVarChar, 10)
param2.Value <- policyName
cmd.Parameters.Add(param2) |> ignore
Some(cmd)
)
|> Option.bind (fun cmd -> SqlUtility.ExecuteReader cmd)
|> Option.bind (fun rdr -> ExtractValue rdr)
let GetSqlConnection (conName : string) =
let conStr = ConfigHandler.GetConnectionString conName
try
let con = new SqlConnection(conStr)
con.Open()
Some(con)
with
| :? System.Exception as ex -> printfn "Failed to connect to DB %s with Error %s " conName ex.Message; None
| _ -> printfn "Failed to connect to DB %s" conName; None
let GetSqlCommand (spName : string) (con : SqlConnection) =
let cmd = new SqlCommand()
cmd.Connection <- con
cmd.CommandText <- spName
cmd.CommandType <- CommandType.StoredProcedure
Some(cmd)
let AddParameters (cmd : SqlCommand) (paramList : SqlParameter list) =
paramList |> List.iter (fun p -> cmd.Parameters.Add p |> ignore)
let ExecuteReader (cmd : SqlCommand ) =
try
Some(cmd.ExecuteReader())
with
| :? System.Exception as ex -> printfn "Failed to execute reader with error %s" ex.Message; None
I have multiple problems with this code
First and foremost the repeated use of Option.bind is very irritating... and is adding noise. I need a more clearer way to check if the output was None and if not then proceed.
At the end there should be a cleanupfunction where I should be able to close + dispose the reader, command and connection. But currently at the end of the pipeline all I have is the reader.
The function which is adding parameters... it looks like it is modifying the "state" of the command parameter because the return type is still the same command which was sent it... with some added state. I wonder how a more experienced functional programmer would have done this.
Visual Studio gives me a warning at each of the place where i do exception handling. what's wrong with that" it says
This type test or downcast will always hold
The way I want this code to look is this
let x : MyRecord seq = GetConnection "con" |> GetCommand "cmd" |> AddParameter "#name" SqlDbType.NVarchar 50 |> AddParameter "#policyname" SqlDbType.NVarchar 50 |> ExecuteReader |> FunctionToReadAndGenerateSeq |> CleanEverything
Can you recommend how can I take my code to the desired level and also any other improvement?
I think that using options to represent failed computations is more suitable to purely functional langauges. In F#, it is perfectly fine to use exceptions to denote that a computation has failed.
Your code simply turns exceptions into None values, but it does not really handle this situation - this is left to the caller of your code (who will need to decide what to do with None). You may as well just let them handle the exception. If you want to add more information to the exception, you can define your own exception type and throw that instead of leaving the standard exceptions.
The following defines a new exception type and a simple function to throw it:
exception SqlUtilException of string
// This supports the 'printf' formatting style
let raiseSql fmt =
Printf.kprintf (SqlUtilException >> raise) fmt
Using plain .NET style with a few simplifications using F# features, the code looks a lot simpler:
// Using 'use' the 'Dispose' method is called automatically
let connName = ConfigHandler.GetConnectionString "MyDB"
use conn = new SqlConnection(connName)
// Handle exceptions that happen when opening the connection
try conn.Open()
with ex -> raiseSql "Failed to connect to DB %s with Error %s " connName ex.Message
// Using object initializer, we can nicely set the properties
use cmd =
new SqlCommand( Connection = conn, CommandText = "dbo.usp_MyStordProc",
CommandType = CommandType.StoredProcedure )
// Add parameters
// (BTW: I do not think you need to set the type - this will be infered)
let param1 = new SqlParameter("#User", SqlDbType.NVarChar, 50, Value = user)
let param2 = new SqlParameter("#PolicyName", SqlDbType.NVarChar, 10, Value = policyName)
cmd.Parameters.AddRange [| param1; param2 |]
use reader =
try cmd.ExecuteReader()
with ex -> raiseSql "Failed to execute reader with error %s" ex.Message
// Do more with the reader
()
It looks more like .NET code, but that is perfectly fine. Dealing with databases in F# is going to use imperative style and trying to hide that will only make the code confusing. Now, there is a number of other neat F# features you could use - especially the support for dynamic operators ?, which would give you something like:
let connName = ConfigHandler.GetConnectionString "MyDB"
// A wrapper that provides dynamic access to database
use db = new DynamicDatabase(connName)
// You can call stored procedures using method call syntax
// and pass SQL parameters as standard arguments
let rows = db.Query?usp_MyStordProc(user, policy)
// You can access columns using the '?' syntax again
[ for row in rows -> row?Column1, row?Column2 ]
For more information about this, see the following MSDN series:
How to: Dynamically Invoke a Stored Procedure
Step 1: Create a Database and Show the Poll Options
Step 2: Implement Voting for an Option
Related
I am trying to write a F# function that reads a CSV file and returns its lines as a sequence of strings that can be further processed in a pipelined expression. The function should handle all exceptions that can arise when opening and reading a file. This is what I came up with so far:
// takes a filename and returns a sequence of strings
// returns empty sequence in case file could not be opened
let readFile (f : string) =
try
seq {
use r = new StreamReader(f) // if this throws, exception is not caught below
while not r.EndOfStream do
yield reader.ReadLine() // same here
}
with ex
| ex when (ex :? Exception) ->
printfn "Exception: %s" ex.Message
Seq.empty
The problem here is that the exceptions that could be thrown by StreamReader() and ReadLine() are not caught in the exception handler but instead are left uncaught and lead to program termination. Also, there seems to be no way of trying to catch exceptions inside the seq {} sequence expression. Right now I cannot think of any other way to design such a function than reading the whole file into an intermediate collection like a list or an array beforehand and then returning this collection as a sequence to the callers, thereby loosing all the benefits of lazy evaluation.
Has anybody got a better idea ?
The reason the exceptions are not caught by the try-with handler here is that the body of the seq is lazily executed. readFile returns the sequence without generating an exception, but then trying to execute that sequence generates an exception in the context where it is being used.
Since F# doesn't let you use try-with within a sequence expression, you have to be a bit creative here. You could use Seq.unfold to generate the sequence like so, for instance:
let readFile (f: string) =
try
new StreamReader(f)
|> Seq.unfold
(fun reader ->
try
if not reader.EndOfStream then
Some(reader.ReadLine(), reader)
else
reader.Dispose()
None
with ex ->
printfn "Exception while reading line: %O" ex
reader.Dispose()
None)
with ex ->
printfn "Exception while opening the file: %O" ex
Seq.empty
Perhaps a less tricky approach would be to wrap StreamReader.ReadLine so that it doesn't throw exceptions. That way you can still use a seq expression and a use statement.
let readLine (reader: StreamReader) =
try
reader.ReadLine() |> Some
with ex ->
printfn "Exception while reading line: %O" ex
None
let readFile2 (f: string) =
try
let r = new StreamReader(f)
seq {
use reader = r
let mutable error = false
while not error && not reader.EndOfStream do
let nextLine = readLine reader
if nextLine.IsSome then yield nextLine.Value else error <- true
}
with ex ->
printfn "Exception while opening the file: %O" ex
Seq.empty
let readFile (f : string) =
try File.ReadLines(f)
with ex -> printfn "Exception: %s" ex.Message; Seq.empty
I want to write an application that read ip address from xml file. The file looks like
<range>
<start>192.168.40.1</start>
<end>192.168.50.255</end>
<subnet>255.255.255.0</subnet>
<gateway>192.168.50.1</gateway>
</range>
I create an records type to save the ip address
type Scope = { Start: IPAddress; End: IPAddress; Subnetmask: IPAddress; Gateway: IPAddress }
I wrote a unit function, that output the ip's.
loc
|> Seq.iter (fun e -> match e.Name.LocalName with
|"start" -> printfn "Start %s" e.Value
|"end" -> printfn "End %s" e.Value
|"subnet" -> printfn "Subnet %s" e.Value
|"gateway" -> printfn "Gateway %s" e.Value
| _ -> ())
How can I return the scope records type instead of unit?
As mentioned in the comments, the XML type provider makes this a lot easier. You can just point it at a sample file, it will infer the structur and let you read the file easily:
type RangeFile = XmlProvider<"sample.xml">
let range = RangeFile.Load("file-you-want-to-read.xml")
let scope =
{ Start = IPAddress.Parse(range.Start)
End = IPAddress.Parse(range.End)
Subnetmask = IPAddress.Parse(range.Subnet)
Gateway = IPAddress.Parse(range.Gateway) }
That said, you can certainly implement this yourself too. The code you wrote is a good start - there is a number of ways to do this, but in any case, you'll need to do some lookup based on the local name of the element (to find start, end, etc.).
One option is to load all the properties into a dictionary:
let lookup =
loc
|> Seq.map (fun e -> e.Name.LocalName, IPAddress.Parse(e.Value)
|> dict
Now you have a lookup table that contains IPAddress for each of the keys, so you can create Scope value using just:
let scope =
{ Start = lookup.["start"]; End = lookup.["end"];
Subnetmask = lookup.["subnet"]; Gateway = lookup.["gateway"] }
That said, the nice thing about the XML type provider is that it removes the need to do lookup based on string values and so you are less likely to make mistakes caused by typos.
Is there any way to call a function by name in F#? Given a string, I want to pluck a function value from the global namespace (or, in general, a given module), and call it. I know the type of the function already.
Why would I want to do this? I'm trying to work around fsi not having an --eval option. I have a script file that defines many int->() functions, and I want to execute one of them. Like so:
fsianycpu --use:script_with_many_funcs.fsx --eval "analyzeDataSet 1"
My thought was to write a trampoline script, like:
fsianycpu --use:script_with_many_funcs.fsx trampoline.fsx analyzeDataSet 1
In order to write "trampoline.fsx", I'd need to look up the function by name.
There is no built-in function for this, but you can implement it using .NET reflection. The idea is to search through all types available in the current assembly (this is where the current code is compiled) and dynamically invoke the method with the matching name. If you had this in a module, you'd have to check the type name too.
// Some sample functions that we might want to call
let hello() =
printfn "Hello world"
let bye() =
printfn "Bye"
// Loader script that calls function by name
open System
open System.Reflection
let callFunction name =
let asm = Assembly.GetExecutingAssembly()
for t in asm.GetTypes() do
for m in t.GetMethods() do
if m.IsStatic && m.Name = name then
m.Invoke(null, [||]) |> ignore
// Use the first command line argument (after -- in the fsi call below)
callFunction fsi.CommandLineArgs.[1]
This runs hello world when called by:
fsi --use:C:\temp\test.fsx --exec -- "hello"
You can use reflection to get the functions as MethodInfo's by FSharp function name
open System
open System.Reflection
let rec fsharpName (mi:MemberInfo) =
if mi.DeclaringType.IsNestedPublic then
sprintf "%s.%s" (fsharpName mi.DeclaringType) mi.Name
else
mi.Name
let functionsByName =
Assembly.GetExecutingAssembly().GetTypes()
|> Seq.filter (fun t -> t.IsPublic || t.IsNestedPublic)
|> Seq.collect (fun t -> t.GetMethods(BindingFlags.Static ||| BindingFlags.Public))
|> Seq.filter (fun m -> not m.IsSpecialName)
|> Seq.groupBy (fun m -> fsharpName m)
|> Map.ofSeq
|> Map.map (fun k v -> Seq.exactlyOne v)
You can then invoke the MethodInfo
functionsByName.[fsharpFunctionNameString].Invoke(null, objectArrayOfArguments)
But you probably need to do more work to parse your string arguments using the MethodInfo.GetParameters() types as a hint.
You could also use FSharp.Compiler.Service to make your own fsi.exe with an eval flag
open System
open Microsoft.FSharp.Compiler.Interactive.Shell
open System.Text.RegularExpressions
[<EntryPoint>]
let main(argv) =
let argAll = Array.append [| "C:\\fsi.exe" |] argv
let argFix = argAll |> Array.map (fun a -> if a.StartsWith("--eval:") then "--noninteractive" else a)
let optFind = argv |> Seq.tryFind (fun a -> a.StartsWith "--eval:")
let evalData = if optFind.IsSome then
optFind.Value.Replace("--eval:",String.Empty)
else
String.Empty
let fsiConfig = FsiEvaluationSession.GetDefaultConfiguration()
let fsiSession = FsiEvaluationSession(fsiConfig, argFix, Console.In, Console.Out, Console.Error)
if String.IsNullOrWhiteSpace(evalData) then
fsiSession.Run()
else
fsiSession.EvalInteraction(evalData)
0
If the above was compiled into fsieval.exe it could be used as so
fsieval.exe --load:script_with_many_funcs.fsx --eval:analyzeDataSet` 1
I have a FileReader class whose job is to read and process text files using a StreamReader. To facilitate unit testing, I'd like to provide a type parameter to this class so that I can swap the StreamReader for a FakeReader that doesn't actually interact with the file system (and maybe throws exceptions such as OutOfMemory, so I can test the error handling in FileReader).
Ideally, I'd like to define FileReader something like this (trivialized for clarity):
type FileReader<'Reader> =
member this.Read file =
use sr = new 'Reader(file)
while not sr.EndOfStream do
printfn "%s" <| sr.ReadLine()
and simply define FakeReader to have a constructor that takes the file name, the EndOfStream property getter, the ReadLine() method, and the (empty) Dispose() method. However, F# has several complaints about this type definition, including "Calls to object constructors on type parameters cannot be given arguments." Since StreamReader has no default constructor, this approach seems like a no-go.
So far the only way I've gotten this to work is to inherit FakeReader from StreamReader:
type FakeReader() =
inherit StreamReader("") with
override this.ReadLine() = "go away"
member this.EndOfStream = false
member this.Dispose() = ()
and use a factory method that returns either a new FakeReader or a new StreamReader as appropriate.
type ReaderType = Fake | SR
let readerFactory (file : string, readerType) =
match readerType with
| Fake -> new FakeReader() :> StreamReader
| SR -> new StreamReader(file)
type FileReader(readertype) =
member this.Read file =
use sr = readerFactory(file, readertype)
while not sr.EndOfStream do
printfn "%s" <| sr.ReadLine()
This seems a lot less elegant. Is there a way to do this with a type parameter? Thanks to all.
Using a function that creates a reader object (as suggested by MizardX) is the direct answer to your question. However, I'd maybe consider using a different abstraction than TextReader). As Ankur mentioned in a comment, you could use a more functional approach.
If you're just reading lines of text from the input using TextReader, you could use a seq<string> type instead. The FileReader type may actually be just a function taking seq<string> (although that may be oversimplification... it depends).
This makes it more "functional" - in functional programming, you're often transforming data structures using functions, which is exactly what this example does:
open System.IO
/// Creates a reader that reads data from a file
let readFile (file:string) = seq {
use rdr = new StreamReader(file)
let line = ref ""
while (line := rdr.ReadLine(); !line <> null) do
yield !line }
/// Your function that processes the input (provided as a sequence)
let processInput input =
for s in input do
printfn "%s" s
readFile "input.txt" |> processInput
To test the processInput function, you could then create a new seq<string> value. This is significantly easier than implementing a new TextReader class:
let testInput = seq {
yield "First line"
yield "Second line"
raise <| new System.OutOfMemoryException() }
testInput |> processInput
You could pass in a function that constructs and returns an object of your desired type.
type FileReader(f : string -> TextReader) =
member this.Read file =
use sr = f file
while sr.Peek() <> -1 do
printfn "%s" <| sr.ReadLine()
type FakeReader() =
inherit StringReader("")
override this.ReadLine() = "go away"
override this.Peek() = 0
let reader1 = new FileReader(fun fn -> new StreamReader(fn) :> _)
let reader2 = new FileReader(fun fn -> new FakeReader() :> _)
Cast was necessary because I dropped the generic type-argument, but the actual type can be inferred.
I just finish writing my first F# program. Functionality wise the code works the way I wanted, but not sure if the code is efficient. I would much appreciate if someone could review the code for me and point out the areas where the code can be improved.
Thanks
Sudaly
open System
open System.IO
open System.IO.Pipes
open System.Text
open System.Collections.Generic
open System.Runtime.Serialization
[<DataContract>]
type Quote = {
[<field: DataMember(Name="securityIdentifier") >]
RicCode:string
[<field: DataMember(Name="madeOn") >]
MadeOn:DateTime
[<field: DataMember(Name="closePrice") >]
Price:float
}
let m_cache = new Dictionary<string, Quote>()
let ParseQuoteString (quoteString:string) =
let data = Encoding.Unicode.GetBytes(quoteString)
let stream = new MemoryStream()
stream.Write(data, 0, data.Length);
stream.Position <- 0L
let ser = Json.DataContractJsonSerializer(typeof<Quote array>)
let results:Quote array = ser.ReadObject(stream) :?> Quote array
results
let RefreshCache quoteList =
m_cache.Clear()
quoteList |> Array.iter(fun result->m_cache.Add(result.RicCode, result))
let EstablishConnection() =
let pipeServer = new NamedPipeServerStream("testpipe", PipeDirection.InOut, 4)
let mutable sr = null
printfn "[F#] NamedPipeServerStream thread created, Wait for a client to connect"
pipeServer.WaitForConnection()
printfn "[F#] Client connected."
try
// Stream for the request.
sr <- new StreamReader(pipeServer)
with
| _ as e -> printfn "[F#]ERROR: %s" e.Message
sr
while true do
let sr = EstablishConnection()
// Read request from the stream.
printfn "[F#] Ready to Receive data"
sr.ReadLine()
|> ParseQuoteString
|> RefreshCache
printfn "[F#]Quot Size, %d" m_cache.Count
let quot = m_cache.["MSFT.OQ"]
printfn "[F#]RIC: %s" quot.RicCode
printfn "[F#]MadeOn: %s" (String.Format("{0:T}",quot.MadeOn))
printfn "[F#]Price: %f" quot.Price
In general, you should try using immutable data types and avoid imperative constructs such as global variables and imperative loops - although using them in F# is fine in many cases, they should be used only when there is a good reason for doing so. Here are a couple of examples where you could use functional approach:
First of all, to make the code more functional, you should avoid using global mutable cache. Instead, your RefreshCache function should return the data as the result (preferably using some functional data structure, such as F# Map type):
let PopulateCache quoteList =
quoteList
// Generate a sequence of tuples containing key and value
|> Seq.map (fun result -> result.RicCode, result)
// Turn the sequence into an F# immutable map (replacement for hashtable)
|> Map.ofSeq
The code that uses it would be changed like this:
let cache =
sr.ReadLine()
|> ParseQuoteString
|> PopulateCache
printfn "[F#]Quot Size, %d" m_cache.Count
let quot = m_cache.["MSFT.OQ"]
// The rest of the sample stays the same
In the EstablishConnection function, you definitely don't need to declare a mutable variable sr, because in case of an exception, the function will return null. I would instead use option type to make sure that this case is handled:
let EstablishConnection() =
let pipeServer =
new NamedPipeServerStream("testpipe", PipeDirection.InOut, 4)
printfn "[F#] NamedPipeServerStream thread created..."
pipeServer.WaitForConnection()
printfn "[F#] Client connected."
try // Wrap the result in 'Some' to denote success
Some(new StreamReader(pipeServer))
with e ->
printfn "[F#]ERROR: %s" e.Message
// Return 'None' to denote a failure
None
The main loop can be written using a recursive function that stops when EstablishConnection fails:
let rec loop() =
match EstablishConnection() with
| Some(conn) ->
printfn "[F#] Ready to Receive data"
// rest of the code
loop() // continue looping
| _ -> () // Quit
Just a couple thoughts...
You probably want a 'use' rather than a 'let' in a few places, as I think some of the objects in the program are IDisposable.
You may consider wrapping the EstablishConnection method and the final while loop in async blocks (and make other minor changes), so that e.g. you can wait asynchronously for connections without blocking a thread.
At first glance it is written in imperative style rather than functional style, which does make sense given that most of the program involves side effects (i.e. I/O). Line for line, it almost looks like a C# program.
Given the amount of I/O that is taking place, I don't know that there is much you can do to this particular program to make it more of a functional style of coding.