Why does 'printf "%A" None' output null - f#

Why does printf output Some x for Some x, but <null> for None?
> printfn "%A" (Some 123);;
Some 123
val it : unit = ()
> printfn "%A" None;;
<null>
val it : unit = ()

In compiled code, F# uses the null value to represent the None case of option<'T> for efficiency. You can actually use the same for your own discriminated unions by using the CompilationRepresentationFlags. UseNullAsTrueValue compilation flag (see MSDN documentation).
You can see that this is what's going on by using the Object.ReferenceEquals method:
> let n = None;;
val n : 'a option
> System.Object.ReferenceEquals(n, null);;
val it : bool = true
Why does printfn "%A" just print the internal representation rather than recognizing that this actually represents the None case?
I think the answer is that printing is done dynamically using reflection and so the argument is just converted to a value of type obj at some point. Once you have a value null of type obj, it is not possible to recover what type it was before casting and so you cannot find out that null actually represents None (because null.GetType() fails). Presumably, the printing could use the static type information to get type information that way - but that would probably be more tricky to implement.

This is actually older behavior that won't go away. Tomas' answer is correct for older FSI, but if you install something newer (like .NET Core 3.1 latest, or .NET 5 preview) you'll see with dotnet fsi that None formats as None with your example.

Related

Overload resolution with TryParse

We have a function converting things like Int32.TryParse from using a byref to using an Option for the return value.
let inline ToOptionFunc refFunction x =
match refFunction x with
| true, value -> Some value
| false, _ -> None
Stuff like this stopped compiling in .NET Core with the new overloads to TryParse:
let Int32TryParse (x:string) =
ToOptionFunc Int32.TryParse x // A unique overload for method 'TryParse' could not be determined (...)
I tried many things and accidentally got it to work by writing it like this instead:
let Int32TryParse (x:string) =
x |> ToOptionFunc Int32.TryParse
I just don't understand why this compiles and the former does not.
In .NET Core, the Int32.TryParse function has some extra overloads - it can parse either string or ReadOnlySpan<char>. The original code stopped working, because the compiler did not know which overload you wanted to use.
In the version without pipe, the compiler needs to type-check ToOptionFunc Int32.TryParse x. It proceeds from left to right and when it gets to Int32.TryParse, it does not yet know about x (which has a type annotation constraining that to string) and without knowing about x, it cannot know which TryParse you need.
In the version with pipe, the compiler needs to type-check x |> ToOptionFunc Int32.TryParse. It proceeds from left to right and knows that x is string, so it then infers that the function passed to ToOptionFunc must also be taking string - and when it checks Int32.TryParse, it can already uniquely determine the overload.
The summary is, pipe has very nice properties for guiding type-checking!

F# Seq.choose() Error FS0001

I have tried MSDN's example for the Seq.choose function (written below) in both a .fsx file and the interactive window for Visual Studio, but it repeatedly returns an error FS0001, stating that the "None" option is a PageExt type rather than the abstract option type 'a option.
I have searched in vain for an explanation of the PageExt type or why this could be returning an error when the None keyword should just represent the "no value" option in the match expression.
let numbers = seq {1..20}
let evens = Seq.choose(fun x ->
match x with
| x when x%2=0 -> Some(x)
| _ -> None ) numbers
printfn "numbers = %A\n" numbers
printfn "evens = %A" evens
;;
| _ -> None ) numbers
---------------------------------------^^^^
>
C:Path\stdin(38,40): error FS0001: This expression was expected to have type
'a option
but here has type
PageExt
Thanks for any help anyone can offer!
The PageExt type is likely something that you've pulled into your current FSI session previously which bound something to None, essentially blocking FSI from recognizing the normal option types.
In F#, you can reuse names, which "shadows" the original value. For example, in FSI, if you type:
let a = 1;;
let a = 2.3;;
a;;
You'll notice that it shows:
val a : int = 1
Then
val a : float = 2.3
Finally
val it : float = 2.3
This isn't changing the definition of a, but rather defining a new a name that shadows (or "hides") the original bound value.
In your case, you have a None name that's bound to something with a PageExt type that's shadowing Option.None, preventing it from being usable.
The easiest way to fix this is to reset your FSI session. Right click in the F# Interactive window, and choose "Reset iteractive session". If you do that, then run the code you pasted, it will work fine.

Delegate/Func conversion and misleading compiler error message

I thought that conversions between F# functions and System.Func had to be done manually, but there appears to be a case where the compiler (sometimes) does it for you. And when it goes wrong the error message isn't accurate:
module Foo =
let dict = new System.Collections.Generic.Dictionary<string, System.Func<obj,obj>>()
let f (x:obj) = x
do
// Question 1: why does this compile without explicit type conversion?
dict.["foo"] <- fun (x:obj) -> x
// Question 2: given that the above line compiles, why does this fail?
dict.["bar"] <- f
The last line fails to compile, and the error is:
This expression was expected to have type
System.Func<obj,obj>
but here has type
'a -> obj
Clearly the function f doesn't have a signature of 'a > obj. If the F# 3.1 compiler is happy with the first dictionary assignment, then why not the second?
The part of the spec that should explain this is 8.13.7 Type Directed Conversions at Member Invocations. In short, when invoking a member, an automatic conversion from an F# function to a delegate will be applied. Unfortunately, the spec is a bit unclear; from the wording it seems that this conversion might apply to any function expression, but in practice it only appears to apply to anonymous function expressions.
The spec is also a bit out of date; in F# 3.0 type directed conversions also enable a conversion to a System.Linq.Expressions.Expression<SomeDelegateType>.
EDIT
In looking at some past correspondence with the F# team, I think I've tracked down how a conversion could get applied to a non-syntactic function expression. I'll include it here for completeness, but it's a bit of a strange corner case, so for most purposes you should probably consider the rule to be that only syntactic functions will have the type directed conversion applied.
The exception is that overload resolution can result in converting an arbitrary expression of function type; this is partly explained by section 14.4 Method Application Resolution, although it's pretty dense and still not entirely clear. Basically, the argument expressions are only elaborated when there are multiple overloads; when there's just a single candidate method, the argument types are asserted against the unelaborated arguments (note: it's not obvious that this should actually matter in terms of whether the conversion is applicable, but it does matter empirically). Here's an example demonstrating this exception:
type T =
static member M(i:int) = "first overload"
static member M(f:System.Func<int,int>) = "second overload"
let f i = i + 1
T.M f |> printfn "%s"
EDIT: This answer explains only the mysterious promotion to 'a -> obj. #kvb points out that replacing obj with int in OPs example still doesn't work, so that promotion is in itself insufficient explanation for the observed behaviour.
To increase flexibility, the F# type elaborator may under certain conditions promote a named function from f : SomeType -> OtherType to f<'a where 'a :> SomeType> : 'a -> OtherType. This is to reduce the need for upcasts. (See spec. 14.4.2.)
Question 2 first:
dict["bar"] <- f (* Why does this fail? *)
Because f is a "named function", its type is promoted from f : obj -> obj following sec. 14.4.2 to the seemingly less restrictive f<'a where 'a :> obj> : 'a -> obj. But this type is incompatible with System.Func<obj, obj>.
Question 1:
dict["foo"] <- fun (x:obj) -> x (* Why doesn't this, then? *)
This is fine because the anonymous function is not named, and so sec. 14.4.2 does not apply. The type is never promoted from obj -> obj and so fits.
We can observe the interpreter exhibit behaviour following 14.4.2:
> let f = id : obj -> obj
val f : (obj -> obj) (* Ok, f has type obj -> obj *)
> f
val it : ('a -> obj) = <fun:it#135-31> (* f promoted when used. *)
(The interpreter doesn't output constraints to obj.)

Active pattern broken in F# 3.0

This active pattern compiles with F# 2.0:
let (|Value|_|) value = // 'a -> 'T option
match box value with
| :? 'T as x -> Some x
| _ -> None
but, in F# 3.0, emits the error:
Active pattern '|Value|_|' has a result type containing type variables that are not determined by the input. The common cause is a [sic] when a result case is not mentioned, e.g. 'let (|A|B|) (x:int) = A x'. This can be fixed with a type constraint, e.g. 'let (|A|B|) (x:int) : Choice = A x'
I tried:
let (|Value|_|) value : 'T option = ...
and:
let (|Value|_|) (value: 'U) = ...
How can it be fixed?
Environments: Visual Studio 2012 (RTM) and FSI v11.0.50727.1
EDIT: Here's a simpler repro:
let (|X|) x = unbox x
There was a bug in the F# 2.0 compiler where the compiler did incorrect analysis and bad code generation for certain Active Patterns with free type variables in the result; a simple repro is
let (|Check|) (a : int) = a, None
//let (|Check|) (a : int) = a, (None : int option)
let check a =
match a with
| Check (10, None) -> System.Console.WriteLine "10"
| Check (20, None) -> System.Console.WriteLine "20"
check 10
check 20
which generates a weird warning at compile-time and compiles into seemingly incorrect code. I am guessing that our attempt to fix this bug (and restrict some crazy cases) in F# 3.0 also broke some legal code as collateral damage of the fix.
I'll file another bug, but for F# 3.0, it sounds like you'll need to use one of the workarounds mentioned in other answers.
I did not install the new version yet, but I agree this looks a bit fishy. I guess there may be a good reason for this restriction, but your example in the other question seems quite compeling.
As a workaround, I think that adding a witness parameter (that is not used, but hints what the type of the result is going to be) could work:
let (|Value|_|) (witness:unit -> 'T) value : 'T option =
match box value with
| :? 'T as x -> Some x
| _ -> None
Of course, this makes the use a bit uglier, because you need to come up with some argument. In the above, I used witness of type unit -> 'T, hoping that the following might compile:
let witness () : 'T = failwith "!"
match box 1 with
| Value witness 1 -> printfn "one"
If that does not work, then you can probably try using witness parameter of type 'T (but then you have to provide an actual function, rather than just a generic function).
for the sake of completeness, one more workaround:
type Box<'R> = Box of obj
let (|Value|_|) ((Box x) : Box<'R> ) : 'R option =
match x with
| :? 'R as x -> Some x
| _ -> None
let check t =
match Box t with
| Value 1 -> printfn "one"
| Value 2 -> printfn "two"
check 1 // one
check 2 // two
however it still will suffer from the problem mentioned by #kvb in another thread. Personally I'll prefer #kvb's version with parameterized active pattern.
See my answer to your other question for some thoughts on how to work around the issue and one reason that such active patterns might be undesirable. I'm not sure whether the breaking change was intended.

How do I customize output of a custom type using printf?

I've read through a good chunk of Expert F# and am working on building an actual application. While debugging, I've grown accustomed to passing fsi commands like this to make things legible in the repl window:
fsi.AddPrinter(fun (x : myType) -> myType.ToString())
I would like to extend this to work with the printf formatter, so I could type e.g.
printf "%A" instanceOfMyType
and control the output for a custom type. The book implies that this can be done (p 93, "Generic structural formatting can be extended to work with any user-defined data types,
a topic covered on the F# website"), but I have failed to find any references as to how to actually accomplish this. Does anyone know how? Is it even possible?
Edit:
I should have included a code sample, it's a record type that I'm dealing with, e.g.
type myType =
{a: int}
override m.ToString() = "hello"
let t = {a=5}
printfn "%A" t
printfn "%A" (box t)
both print statements yield:
{a = 5;}
It looks like the Right Way to do this in F# 2.0 is by using the StructuredFormatDisplay attribute, for example:
[<StructuredFormatDisplay("hello {a}")>]
type myType = {a: int}
In this example, instead of the default {a = 42;}, you would get hello 42.
This works the same way for object, record, and union types. And although the pattern must be of the format "PreText {PropertyName} PostText" (PreText and PostText being optional), this is actually more powerful than ToString() because:
PropertyName can be a property of any type. If it is not a string, then it will also be subject to structured formatting. Don Syme's blog gives an example of recursively formatting a tree in this way.
It may be a calculated property. So you could actually get ToString() to work for record and union types, though in a rather round-about way:
[<StructuredFormatDisplay("{AsString}")>]
type myType =
{a: int}
override m.ToString() = "hello"
member m.AsString = m.ToString() // a property that calls a method
By the way, ToString() will always be used (even for record and union types) if you call printfn "%O" instead of printfn "%A".
Hmm... I vaguely recall some changes to this, but I forget if they happened before or after the CTP (1.9.6.2).
In any case, on the CTP, I see that
type MyType() =
override this.ToString() = "hi"
let x = new MyType()
let xs = Array.create 25 x
printfn "%A" x
printfn "%A" xs
when evaluated in the VFSI window does what I would want, and that
x;;
xs;;
also prints nicely. So, I guess I am unclear how this differs from what is desired?
If you override ToString method, that should do.

Resources