F# 'unbox float x' vs. 'unbox int x' weird compilation result - f#

This came up while I looked at the following question: F# Unit of Measure, Casting without losing the measure type
Please note that I am not trying to use this unbox code, I just discovered some weird behavior while answering the question.
Why does the following code work
let intToFloat (x:int<'u>) : float<'u> = unbox float x
intToFloat 1<second>
while this yields a System.InvalidCastException: Unable to cast object of type 'float32ToFloat#86-6' to type 'Microsoft.FSharp.Core.FSharpFunc`2[System.Single,System.Double]'.?
let float32ToFloat (x:float32<'u>) : float<'u> = unbox float x
float32ToFloat 1.0f<second>
If I put parantheses around the (float x) the code works as expected, so I assume it must be some expression evaluation/type inference rule. What exactly is going on here and why are the parantheses needed in the second case?

The subtle thing in your code snippets is unbox float x - the compiler treats this as (unbox float) x. As a result the two functions are actually treated like this:
let intToFloat (x:int<'u>) : float<'u> =
let f = unbox float in f x
let float32ToFloat (x:float32<'u>) : float<'u> =
let f = unbox float in f x
So, you are taking the float function, casting it (unsafely) to a function of another type and then calling it. The type is int<'u> -> float<'u> in the first case and float32<'u> -> float<'u> in the second case.
I think the first one works because when the compiler sees the float function (without any type annotations), it defaults to int -> float and, since units of measure are erased at runtime, this can be converted to int<'u> -> float<'u> (but not to the second type - because you are performing unsafe cast).
So, the main problem is wrong parentheses in your implementation (which leads to a really subtle issue). I think you probably wanted something like this:
let intToFloat (x:int<'u>) : float<'u> = unbox (float x)
let float32ToFloat (x:float32<'u>) : float<'u> = unbox (float32 x)

Related

F# value restriction problem in reversing list

The following F# code doesn't compile due to value restriction problem:
let x = List.rev []
But this compiles:
let x = List.rev [] in 3::x
As I understand it, the compiler infers that x must be of type int list so it doesn't compile.
The following doesn't compile:
let x = List.rev [] in (3::x, true::x)
But this does:
let x = ([]) in (3::x, true::x)
Why?
As I understand it*, there are two ways to declare a value in F#:
Value has a concrete type (e.g. List<int>). You must either explicitly specify this concrete type, or the compiler must be able to infer it.
Value has a generic type (e.g. List<'t>). You must either explicitly specify this generic type, or the compiler must be able to infer it and the value must be a simple immutable value.
With that in mind, here are the explanations for what you're seeing:
// not allowed because x is generic, but not simple
let x = List.rev []
// allowed because the compiler can infer x's concrete type (List<int>)
let x = List.rev [] in 3::x
// not allowed because x is generic, but not simple
let x = List.rev [] in (3::x, true::x)
// allowed because x is both generic and simple (compiler can tell it's the empty list)
let x = ([]) in (3::x, true::x)
* The value restriction can be tricky, so there may be nuances I've overlooked in my explanation.

How to do explicit overloaded conversion in F# like in C#? [duplicate]

This question already has an answer here:
How to use overloaded explicit conversion operators?
(1 answer)
Closed 4 years ago.
Let's say that I have a class in C# with overloaded implicit and explicit operators:
public static implicit operator CSClass(int a) => ...;
public static explicit operator int(CSClass a) => ...;
I compile this project as class library.
In F# now I can add my operator for implicit conversions and use it:
#r #"C:\path\to.dll"
open Some.Namespace.ToMyClass
let inline (!>) (x:^a) : ^b = ((^a or ^b) : (static member op_Implicit : ^a -> ^b) x)
let a : CSClass = !> 5
But how can I do an explicit overloaded conversion in F#? (CSClass to int)
It is my understanding that F# does not usually do explicit conversions. Instead, you would just use a function. For example, if you have a char and want to convert that explicitly into an int, in C# you write:
char theChar = 'A';
int convertedChar = (int)theChar;
In F#, the int operator (function) is used for the same purpose:
let theChar = 'A'
let convertedChar = int theChar;
Therefore the idiomatic way to do the conversion would be something like this:
module Some.Namespace.MyClass
let toInt (x : MyClass) = [...]
You would use it like so:
let convertedMyClass = MyClass.toInt myClass
It can also be piped:
funcReturningMyClass x y
|> MyClass.toInt
|> printfn "%d"

What is the difference between float32 vs single and float vs double, if any?

I have always considered the types float32 and single to be interchangeable, in that they are type aliases. The same for float and double. However, they appear to be declared in different assemblies Microsoft.FSharp.Core.Operators vs Microsoft.FSharp.Core.ExtraTopLevelOperators.
Also, the popup description is slightly different, where F# says on float32 and float that it can take a string and use Parse() on it.
However, trying that with single and double succeeds just fine too:
let x = single "12.3"
let y = double "13.4"
Is there any difference I should be aware of? I have always used them interchangeably, never really gave it another thought, until I saw the differences in the popups and in signatures:
// on hovering, or in FSI, this will have the slightly confusing signature:
// val x: a: double -> float
let x (a: double) = float a
All of them are just aliases of the corresponding CLR types as you can see in prim-types-prelude.fs.
type float32 = System.Single
type float = System.Double
type single = System.Single
type double = System.Double
As for the confusing signature consider this:
type typA = A;;
type typB = typA;;
let f (x : typA) = (x : typB)
//val f : x:typA -> typB
Seems like F# prefers to use the aliases at the places you (or some other definition) used them.
Finally the namespaces you are referring to (FSharp.Core.Operators) are referring not to the float type but the float function (float : 'T -> float). See prim-types.fs.

When a function with seq type parameter is a record field, it won't accept list or array any more

Please see the below code.
let x = Seq.head [1.0; 2.0] // This is ok.
type Func<'T> = { f: seq<'T> -> 'T }
let func = { f = Seq.head }
// Compilation error: This expression was expected to have type seq<obj> but here has type 'a list
let y = func.f [1.0; 2.0]
let z = func.f ([1.0; 2.0] |> List.toSeq) // This is ok.
I don't understand why Seq.head and fund.f behavior differently here. It looks like a compiler bug to me. However, if this is by design, can anyone help explain a little bit to me? Thanks a lot!
The below is the answer from Don Syme (github.com/fsharp):
This is by design. The rule called "14.4.3 Implicit Insertion of Flexibility for Uses of Functions and Members" is only applied to uses of functions and members, not uses of record fields.

Why does F# constrain my code and remove generics?

type VBO<'T when 'T : (new : unit -> 'T) and 'T : struct and 'T :> ValueType> =
{ Handle : int
target : BufferTarget
size : int
dataSize : int
data : 'T []
pos : int
usage : BufferUsageHint }
type VBO =
static member Create(target, size, pos, usage, (data : Vector3 [])) =
VBO.CreateImpl(target, size, pos, usage, Vector2.SizeInBytes, data)
// Type mismatch. Expecting Vector3 but found Vector2
static member Create(target, size, pos, usage, (data : Vector2 [])) =
VBO.CreateImpl(target, size, pos, usage, Vector2.SizeInBytes, data)
// This construct causes code to be less generic than indicated by the type annotations.
// The type variable 'T has been constrained to be type 'Vector3'.
static member CreateImpl(target, size, pos, usage, dataSize, (data : 'T [])) =
let h = GL.GenBuffer()
{ Handle = h
target = target
size = size
dataSize = dataSize
data = data
pos = pos
usage = usage }
F# tries to constrain my code but I want it to be generic. I don't really care about what type the data is I just need it pass in the correct dataSize.
What have I done wrong?
The F# compiler seems to specialise generic types if they are used at a particular instantiation in the same block of code. Try splitting up your declaration like this:
type VBO<'T when 'T : (new : unit -> 'T) and 'T : struct and 'T :> ValueType> =
{ Handle : int
target : BufferTarget
size : int
dataSize : int
data : 'T []
pos : int
usage : BufferUsageHint }
type VBO =
static member CreateImpl(target, size, pos, usage, dataSize, (data : 'T [])) =
let h = GL.GenBuffer()
{ Handle = h
target = target
size = size
dataSize = dataSize
data = data
pos = pos
usage = usage }
type VBO with
static member Create(target, size, pos, usage, (data : Vector3 [])) =
VBO.CreateImpl(target, size, pos, usage, Vector2.SizeInBytes, data)
static member Create(target, size, pos, usage, (data : Vector2 [])) =
VBO.CreateImpl(target, size, pos, usage, Vector2.SizeInBytes, data)
F#'s type inference works top-to-bottom and left-to-right, which occasionally leads to interesting corner cases. In particular, reordering method definitions within a type can affect the inferred types. As Ganesh has pointed out, one solution to your problem is to break your type up into disjoint chunks, but this isn't actually necessary - just putting the generic method first should be sufficient (and note that you can also drop the type annotation on data, if desired).
You can see very similar behavior with simple let rec bindings. Consider:
let rec f() = h 5
and g() = h "test"
and h x = x
When attempting to infer the type of f, the compiler notes that h must take an int as input, which makes g's definition invalid. Reordering the definitions to put h first is the easiest solution (then the compiler can infer a generic type for h before looking at the bodies of f and g, so everything goes through fine).
Alternatively, you can explicitly make h generic and add type annotations to help the compiler out:
let rec f() = h 5
and g() = h "test"
and h<'t> (x:'t) :'t = x
This can be inconvenient since it can require a significant annotation overhead, but there are circumstances where simply reordering definitions is insufficient to allow the compiler to infer the correct types, so it may sometimes be necessary.
I think it is better to look at the code to understand what went wrong.
So here is a simpler example that shows the same problem.
type test =
static member test (data:int) = test.actual(data)
static member test (data:float) =test.actual(data)
static member actual (data:'t) = ()
the problem is that for static member functions, all the types need to be known - or you need a generic type.
I think the simplest solution is to change your code to look like
let actual (data:'t) = ()
type test =
static member test (data:int) = actual(data)
static member test (data:float) =actual(data)
Here, the compiler has much more freedom to alter the let binding to make it generic.

Resources