Cast FsSql Count Result to Int32 without a Compiler Warning - f#

So I'm trying to do a simple count query in FsSql
let! countOption = Sql.asyncExecScalar connectionManager (sprintf "select count(*) from %s" tableName) []
match countOption with
| Some count -> return dbCountToInt32 count
| None _ -> return 0
The result of asyncExecScalar is val countOption : obj option
in my dbCountToInt32 function I have tried the below methods to convert this into an int32.
let dbCountToInt32 i64 =
try
// this throws a conversion exception `Can't cast Int64 to Int32`
// int32(int64(i64))
// this throws invalid cast exception `Can't cast Int64 to Int32`
// int32(i64)
//Works but throws a compiler warning `The type 'int64' does not have any proper subtypes and need not be used as the target of a static coercion`
int32(i64 :> int64)
with
| _ -> 0
Unfortunately as you can see, two of the methods produce an exception and one works fine but has a compiler warning. Is there a way to make it work without a warning?

This is because you're using the checked-cast operator :>, which has the compiler verify that your cast is valid. In this case, since you know the data in your obj is an int64, you can tell the compiler that you know better by using the unsafe-cast operator :?>.

Depending on what you want to do if/when there is an overflow
open System
let convertToIn32 (i:int64) : int32 =
let max32as64 = Convert.ToInt64(Int32.MaxValue)
if(i > max32as64) then Int32.MaxValue else Convert.ToInt32(i)
printfn "%A" (10L |> convertToIn32)
printfn "converted 64 max is %A and int32 max is %A" (Int64.MaxValue |> convertToIn32) Int32.MaxValue
This will give you the max32 instead of throwing. Usually that is not what you want. There are possibly better and faster ways to handle this but this is clear and compared to a DB query a few conversions are probably ok.

Related

F# How to write a function that takes int list or string list

I'm messing around in F# and tried to write a function that can take an int list or a string list. I have written a function that is logically generic, in that I can modify nothing but the type of the argument and it will run with both types of list. But I cannot generically define it to take both.
Here is my function, without type annotation:
let contains5 xs =
List.map int xs
|> List.contains 5
When I try to annotate the function to take a generic list, I receive a warning FS0064: the construct causes the code to be less generic than indicated by the type annotations. In theory I shouldn't need to annotate this to be generic, but I tried anyway.
I can compile this in two separate files, one with
let stringtest = contains5 ["1";"2";"3";"4"]
and another with
let inttest = contains5 [1;2;3;4;5]
In each of these files, compilation succeeds. Alternately, I can send the function definition and one of the tests to the interpreter, and type inference proceeds just fine. If I try to compile, or send to the interpreter, the function definition and both tests, I receive error FS0001: This expression was expected to have type string, but here has type int.
Am I misunderstanding how typing should work? I have a function whose code can handle a list of ints or a list of strings. I can successfully test it with either. But I can't use it in a program that handles both?
You are running into value restrictions on the automatic generalization of the type inference system as outlined here
Specifically,
Case 4: Adding type parameters.
The solution is to make your function generic rather than just making its parameters generic.
let inline contains5< ^T when ^T : (static member op_Explicit: ^T -> int) > (xs : ^T list) =
List.map int xs
|> List.contains 5
You have to make the function inline because you have to use a statically resolved type parameter, and you have to use a statically resolved type parameter in order to use member constraints to specify that the type must be convertible to an int. As outlined here
You can use inline to prevent the function from being fixed to a particular type.
In FSI, the interactive REPL:
> open System;;
> let inline contains5 xs = List.map int xs |> List.contains 5;;
val inline contains5 :
xs: ^a list -> bool when ^a : (static member op_Explicit : ^a -> int)
> [1;2;3] |> contains5;;
val it : bool = false
> ["1";"2";"5"] |> contains5;;
val it : bool = true
Note that the signature of contains5 has a generic element to it. There's more about inline functions here.
This is already answered correctly above, so I just wanted to chime in with why I think it's a good thing that F# appears to makes this difficult / forces us to lose type safety. Personally I don't see these as logically equivalent:
let inline contains5 xs = List.map int xs |> List.contains 5
let stringTest = ["5.00"; "five"; "5"; "-5"; "5,"]
let intTest = [1;2;3;4;5]
contains5 stringTest // OUTPUT: System.FormatException: Input string was not in a correct format.
contains5 intTest // OUTPUT: true
When inlined, the compiler would create two logically distinct versions of the function. When performed on the list<int> we get a boolean result. When performed on a list<string> we get a boolean result or an exception. I like that F# nudges me towards acknowledging this.
let maybeInt i =
match Int32.TryParse i with
| true,successfullyParsedInteger -> Some successfullyParsedInteger
| _ -> None
let contains5 xs =
match box xs with
| :? list<int> as ixs ->
ixs |> List.contains 5 |> Ok
| :? list<string> as sxs ->
let successList = sxs |> List.map maybeInt |> List.choose id
Ok (successList |> List.contains 5)
| _ ->
Error "Error - this function expects a list<int> or a list<string> but was passed something else."
let stringTest = ["5.00"; "five"; "5"; "-5"; "5,"]
let intTest = [1;2;3;4;5]
let result1 = contains5 stringTest // OUTPUT: Ok true
let result2 = contains5 intTest // OUTPUT: Ok true
Forces me to ask if some of the values in the string list cannot be parsed, should I drop out and fail, or should I just try and look for any match on any successful parse results?.
My approach above is horrible. I'd split the function that operates on the strings from the one that operates on the integers. I think your question was academic rather than a real use case though, so I hope I haven't gone off on too much of a tangent here!
Disclaimer: I'm a beginner, don't trust anything I say.

F# out parameters and value types

The following f# function works great if I pass references to objects, but will not accept structs, or primitives:
let TryGetFromSession (entryType:EntryType, key, [<Out>] outValue: 'T byref) =
match HttpContext.Current.Session.[entryType.ToString + key] with
| null -> outValue <- null; false
| result -> outValue <- result :?> 'T; true
If I try to call this from C# with:
bool result = false;
TryGetFromSession(TheOneCache.EntryType.SQL,key,out result)
I get The Type bool must be a reference type in order to use it as a parameter Is there a way to have the F# function handle both?
The problem is that the null value in outValue <- null restricts the type 'T to be a reference type. If it has null as a valid value, it cannot be a value type!
You can fix that by using Unchecked.defaultOf<'T> instead. This is the same as default(T) in C# and it returns either null (for reference types) or the empty/zero value for value types.
let TryGetFromSession (entryType:EntryType, key, [<Out>] outValue: 'T byref) =
match HttpContext.Current.Session.[entryType.ToString() + key] with
| null -> outValue <- Unchecked.defaultof<'T>; false
| result -> outValue <- result :?> 'T; true
I still think this is not "pretty"/idomatic F# code and would probably do some more seremonial with the following:
let myCast<'T> o =
match box o with
| :? 'T as r -> Some(r)
| _ -> None
let GetFromSession<'T> entryType key =
match HttpContext.Current.Session.[entryType.ToString + key] with
| null -> None
| r -> myCast<'T> r
This is also kind of "safer" and will (should?) not throw any exception, and it removes the null-stuff in F#. In C# it will return and work ok too, but None are returned as null, and if some result, well yeah it will be Some ;-)
Mind that the above code are not tested, not run in any setting or even compiled, so regard it as pseudo code. It might even have other issues...
Check also:
https://msdn.microsoft.com/en-us/library/dd233220.aspx
and
http://fsharpforfunandprofit.com/posts/match-expression/
On the last link especially: Matching on subtypes
On a side note, I do not like the missing checking of entire hierachy from HttpContext to Session are non-null, but that might just be me...
Update for some C# code using None/Some
var x = GetFromSession<MyTypeInSession>(entryType, key)?.Value??defaultValue;
There is absolutely no need for going full arabic, reading from right to left, and from down and up with a pyramidal scheme of ifs and buts and no candy or nuts, for null-checking et al ad nauseam.
And again code is to be regarded as pseudo code...

Why does this produce a value restriction exception?

I've created a function that returns a list containing only the even indexes as shown below:
let rec removeOddIdx xs =
match xs with
|[] -> []
|h::t -> (if t.Length % 2 = 0 then
[h]#removeOddIdx t
else
removeOddIdx t)
It works fine when I call it:
removeOddIdx [1;2;3;];;
However when I call it with an empty list:
removeOddIdx [];;
I get a Value Restriction exception - how come?
I've read up on value restrictions but I don't understand why it happens in my case.
Here is the precise error message:
Testing.fs(13,1): error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : '_a list
Either define 'it' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.
The problem you're having is that the compiler doesn't know what type to give the return value. When you pass it [1;2;3] it can infer that the return type is int list, but if you pass it [], what is the type of the return value? It cannot be inferred from the usage, so you get a value restriction error.
One solution is to give the parameter a type like so:
> removeOddIdx ([]:int list);;
val it : int list = []
The other is to make the function specific rather than generic like this:
> let rec removeOddIdx (xs:int list) =
match xs with
|[] -> []
|h::t -> (if t.Length % 2 = 0 then
[h]#removeOddIdx t
else
removeOddIdx t);;
val removeOddIdx : xs:int list -> int list
> removeOddIdx [];;
val it : int list = []
Outside of the repl this is unlikely to be an issue since the parameter type is likely to be inferred from elsewhere in your code.

F# Pattern-matching by type

How pattern-matching by type of argument works in F#?
For example I'm trying to write simple program which would calculate square root if number provided or return it's argument otherwise.
open System
let my_sqrt x =
match x with
| :? float as f -> sqrt f
| _ -> x
printfn "Enter x"
let x = Console.ReadLine()
printfn "For x = %A result is %A" x (my_sqrt x)
Console.ReadLine()
I get this error:
error FS0008: This runtime coercion or type test from type
'a
to
float
involves an indeterminate type based on information prior
to this program point. Runtime type tests are not allowed
on some types. Further type annotations are needed.
Since sqrt works with float I check for float type, but guess there could be better solution - like check if input is number (in general) and if so, cast it to float?
The problem here is that the type of x is actually a string. Adding that it comes from Console.ReadLine, what kind of information is stored in that string is only possible to determine at runtime. This means that you can't use neither pattern matching, nor pattern matching with coercion here.
But you can use Active Patterns. As what actual data is stored in x is only known at runtime, you have to parse the string and see what is contains.
So suppose you are expecting a float, but you can't be sure since user can input whatever they want. We are going to try and parse our string:
let my_sqrt x =
let success, v = System.Single.TryParse x // the float in F# is represented by System.Single in .NET
if success then sqrt v
else x
But this won't compile:
This expression was expected to have type float32 but here has type string
The problem is that the compiler inferred the function to return a float32, based on the expression sqrt (System.Single.Parse(x)). But then if the x doesn't parse to float, we intend to just return it, and as x is a string we have an inconsistency here.
To fix this, we will have to convert the result of sqrt to a string:
let my_sqrt x =
let success, v = System.Single.TryParse x
if success then (sqrt v).ToString()
else x
Ok, this should work, but it doesn't use pattern matching. So let's define our "active" pattern, since we can't use regular pattern matching here:
let (|Float|_|) input =
match System.Single.TryParse input with
| true, v -> Some v
| _ -> None
Basically, this pattern will match only if the input can be correctly parsed as a floating point literal. Here's how it can be used in your initial function implementation:
let my_sqrt' x =
match x with
| Float f -> (sqrt f).ToString()
| _ -> x
This looks a lot like your function, but note that I still had to add the .ToString() bit.
Hope this helps.
Just quoting the one and only Scott Wlaschin's 'F# for fun and profit' site:
Matching on subtypes You can match on subtypes, using the :? operator,
which gives you a crude polymorphism:
let x = new Object()
let y =
match x with
| :? System.Int32 ->
printfn "matched an int"
| :? System.DateTime ->
printfn "matched a datetime"
| _ ->
printfn "another type"
This only works to find subclasses of a parent class (in this case,
Object). The overall type of the expression has the parent class as
input.
Note that in some cases, you may need to “box” the value.
let detectType v =
match v with
| :? int -> printfn "this is an int"
| _ -> printfn "something else"
// error FS0008: This runtime coercion or type test from type 'a to int
// involves an indeterminate type based on information prior to this program point.
// Runtime type tests are not allowed on some types. Further type annotations are needed.
The message tells you the problem: “runtime type tests are not allowed
on some types”. The answer is to “box” the value which forces it into
a reference type, and then you can type check it:
let detectTypeBoxed v =
match box v with // used "box v"
| :? int -> printfn "this is an int"
| _ -> printfn "something else"
//test
detectTypeBoxed 1
detectTypeBoxed 3.14
In my opinion, matching and dispatching on types is a code smell, just
as it is in object-oriented programming. It is occasionally necessary,
but used carelessly is an indication of poor design.
In a good object oriented design, the correct approach would be to use
polymorphism to replace the subtype tests, along with techniques such
as double dispatch. So if you are doing this kind of OO in F#, you
should probably use those same techniques.

What am I doing wrong in this F# code?

let parallelTest n = Color(Color.DeepPink, Triangles(sphere n));;
Parallel.For(0,10,new Action(parallelTest));;
Error message :
error FS0001: Type mismatch. Expecting a
int -> unit
but given a
int -> scene.
The type 'unit' does not match the type 'scene'
I'll glad if some body help me.
Compose your function with ignore to make it return unit:
Parallel.For(0, 10, parallelTest >> ignore)
If you want 10 results, perhaps you want
[| for i in 0..9 do
async { return parallelTest i } |]
|> Async.Parallel
|> Async.RunSynchronously
This will return an array of 10 scene results.
At which position does this error message occur? (I can't reproduce the error since I don't know the delcarations of some functions you use)
I guess the following: Parallel.For expects a int -> unit (Action<int> in standard .NET), but parallelTest has a different type (int -> scene) which is therefore incompatible.
And what are you trying to achieve with the whole code?

Resources