Why upcast is not necessary in this let bound function? - f#

According to MSDN
Upcasting is applied automatically when you pass arguments to methods
on an object type. However, for let-bound functions in a module,
upcasting is not automatic, unless the parameter type is declared as a
flexible type.
But
type C() =
member this.T() = ()
type D() =
inherit C()
let myfun (x: C)=
()
let d = D()
myfun d
I don't need to upcast at all.

Have a look at the F# spec where it says:
This means that F# functions whose inferred type includes an unsealed type in argument position may be passed subtypes when called, without the need for explicit upcasts. For example:
(The example showed there is almost the same as yours)
Also note that for let bound functions upcasting is automatically except in some cases, for example when the argument is composed, if your function was:
let myfun (x: C option)=
()
upcast is no longer automatically.

Related

This expression was expected to have type 'unit' but here has type 'string'

I was attempting to convert this to F# but I can't figure out what I'm doing wrong as the error message (in title) is too broad of an error to search for, so I found no resolutions.
Here is the code:
let getIP : string =
let host = Dns.GetHostEntry(Dns.GetHostName())
for ip in host.AddressList do
if ip.AddressFamily = AddressFamily.InterNetwork then
ip.ToString() // big fat red underline here
"?"
A for loop in F# is for running imperative-style code, where the code inside the for loop does not produce a result but instead runs some kind of side-effect. Therefore, the expression block in an F# for loop is expected to produce the type unit, which is what side-effect functions should return. (E.g., printfn "Something" returns the unit type). Also, there's no way to exit a for loop early in F#; this is by design, and is another reason why a for loop isn't the best approach to do what you're trying to do.
What you're trying to do is go through a list one item at a time, find the first item that matches some condition, and return that item (and, if the item is not found, return some default value). F# has a specialized function for that: Seq.find (or List.find if host.AddressList is an F# list, or Array.find if host.AddressList is an array. Those three functions take different input types but all work the same way conceptually, so from now on I'll focus on Seq.find, which takes any IEnumerable as input so is most likely to be what you need here).
If you look at the Seq.find function's type signature in the F# docs, you'll see that it is:
('T -> bool) -> seq<'T> -> 'T
This means that the function takes two parameters, a 'T -> bool and seq<'T> and returns a 'T. The 'T syntax means "this is a generic type called T": in F#, the apostrophe means that what follows is the name of a generic type. The type 'T -> bool means a function that takes a 'T and returns a Boolean; i.e., a predicate that says "Yes, this matches what I'm looking for" or "No, keep looking". The second argument to Seq.find is a seq<'T>; seq is F#'s shorter name for an IEnumerable, so you can read this as IEnumerable<'T>. And the result is an item of type 'T.
Just from that function signature and name alone, you can guess what this does: it goes through the sequence of items and calls the predicate for each one; the first item for which the predicate returns true will be returned as the result of Seq.find.
But wait! What if the item you're looking for isn't in the sequence at all? Then Seq.find will throw an exception, which may not be the behavior you're looking for. Which is why the Seq.tryFind function exists: its function signature looks just like Seq.find, except for the return value: it returns 'T option rather than 'T. That means that you'll either get a result like Some "ip address" or None. In your case, you intend to return "?" if the item isn't found. So you want to convert a value that's either Some "ip address or None to either "ip address" (without the Some) or "?". That is what the defaultArg function is for: it takes a 'T option, and a 'T representing the default value to return if your value is None, and it returns a plain 'T.
So to sum up:
Seq.tryFind takes a predicate function and a sequence, and returns a 'T option. In your case, this will be a string option
defaultArg takes a 'T option and a default value, and returns a normal 'T (in your case, a string).
With these two pieces, plus a predicate function you can write yourself, we can do what you're looking for.
One more note before I show you the code: you wrote let getIP : string = (code). It seems like you intended for getIP to be a function, but you didn't give it any parameters. Writing let something = (code block) will create a value by running the code block immediately (and just once) and then assigning its result to the name something. Whereas writing let something() = (code block) will create a function. It will not run the code block immediately, but it will instead run the code block every time the function is called. So I think you should have written let getIP() : string = (code).
Okay, so having explained all that, let's put this together to give you a getIP function that actually works:
let getIP() = // No need to declare the return type, since F# can infer it
let isInternet ip = // This is the predicate function
// Note that this function isn't accessible outside of getIP()
ip.AddressFamily = AddressFamily.InterNetwork
let host = Dns.GetHostEntry(Dns.GetHostName())
let maybeIP = Seq.tryFind isInternet host.AddressList
defaultArg maybeIP "?"
I hope that's clear enough; if there's anything you don't understand, let me know and I'll try to explain further.
Edit: The above has one possible flaw: the fact that F# may not be able to infer the type of the ip argument in isInternet without an explicit type declaration. It's clear from the code that it needs to be some class with an .AddressFamily property, but the F# compiler can't know (at this point in the code) which class you intend to pass to this predicate function. That's because the F# compiler is a single-pass compiler, that works its way through the code in a top-down, left-to-right order. To be able to infer the type of the ip parameter, you might need to rearrange the code a little, as follows:
let getIP() = // No need to declare the return type, since F# can infer it
let host = Dns.GetHostEntry(Dns.GetHostName())
let maybeIP = host.AddressList |> Seq.tryFind (fun ip -> ip.AddressFamily = AddressFamily.InterNetwork)
defaultArg maybeIP "?"
This is actually more idiomatic F# anyway. When you have a predicate function being passed to Seq.tryFind or other similar functions, the most common style in F# is to declare that predicate as an anonymous function using the fun keyword; this works just like lambdas in C# (in C# that predicate would be ip => ip.AddressFamily == AddressFamily.InterNetwork). And the other thing that's common is to use the |> operator with things like Seq.tryFind and others that take predicates. The |> operator basically* takes the value that's before the |> operator and passes it as the last parameter of the function that's after the operator. So foo |> Seq.tryFind (fun x -> xyz) is just like writing Seq.tryFind (fun x -> xyz) foo, except that foo is the first thing you read in that line. And since foo is the sequence that you're looking in, and fun x -> xyz is how you're looking, that feels more natural: in English, you'd say "Please look in my closet for a green shirt", so the concept "closet" comes up before "green shirt". And in idiomatic F#, you'd write closet |> Seq.find (fun shirt -> shirt.Color = "green"): again, the concept "closet" comes up before "green shirt".
With this version of the function, F# will encounter host.AddressList before it encounters fun ip -> ..., so it will know that the name ip refers to one item in host.AddressList. And since it knows the type of host.AddressList, it will be able to infer the type of ip.
* There's a lot more going on behind the scenes with the |> operator, involving currying and partial application. But at a beginner level, just think of it as "puts a value at the end of a function's parameter list" and you'll have the right idea.
In F# any if/else/then-statement must evaluate to the same type of value for all branches. Since you've omitted the else-branch of the expression, the compiler will infer it to return a value of type unit, effectively turning your if-expression into this:
if ip.AddressFamily = AddressFamily.InterNetwork then
ip.ToString() // value of type string
else
() // value of type unit
Scott Wlaschin explains this better than me on the excellent F# for fun and profit.
This should fix the current error, but still won't compile. You can solve this either by translating the C#-code more directly (using a mutable variable for the localIP value, and doing localIP <- ip.ToString() in your if-clause, or you could look into a more idiomatic approach using something like Seq.tryFind.

The parameter has been used in a way that constrains it to always be DerrivedType

Hi I just started programming in F# and am stuck on a type issue.
I have this function:
member private this.UpdateStats<'T when 'T :> StatisticsBase>(passed: bool, stats: 'T) =
//more stuff..
stats
I'm calling it like this:
this.UpdateStats<GroupStats>(true, GroupStats(Id = Guid.NewGuid()))
The compiler says:
The parameter has been used in a way that constrains it to always be GroupStats.
GroupStats inherit from StatisticsBase. What do I have to do to make the function usable for all entities that inherit from StatisticsBase?
types:
[<AllowNullLiteral>]
type StatisticsBase() =
member val Id = String.Empty with get,set
[<AllowNullLiteral>]
type GroupStats() =
inherit Stats()
StatisticsBase actually inherits from a C# type and is used in a repository, but I can reproduce the error with the code above
After much back and forth, we have been able to ascertain that your actual non-working code is like this (tip for the future: provide more information):
type SomeType() =
member this.M2() =
this.M<GroupStats>(true, GroupStats())
member private this.M<'T when 'T :> Stats>(x: bool, t: 'T) =
t
This code will indeed produce the described error. This is because F# type inference works top-to-bottom, left-to-right. But there is an exception: classes (and other mutually recusrive definition groups) get two passes of type inference - first signatures, then bodies.
When the compiler first comes across the body of M2, it determines that method M must return GroupStats. Later, when the compiler comes across the body of M, it sees that M's return value is the same as parameter t, which means that M must return 'T. But since the compiler already knows, from examining the body of M2, that M must return GroupStats, it follows that 'T must be GroupStats.
This doesn't happen if M is defined before M2: in this case, type inference will first encounter the body of M and correctly determine its return type to be 'T, which will then match up with the body of M2, and the will be no problem.
From the above, two solutions can be formulated: first, you could define M before M2. Second, you could just explicitly specify the return type of M:
member private this.M<'T when 'T :> Stats>(x: bool, t: 'T): 'T =
t
This way, its return type will become known after the first pass, and the problem disappears.

Distinguishing between f# overloaded functions with optional parameters

F# allows overloaded functions to differ only by an optional parameter, for example:
type MyClass() =
member this.func(a: string, b:string) = "func(a,b)"
member this.func(a: string, ?b:string) = "func(a,?b)"
How would you call the first function?
I don't think there is a sensible way to call the first function if the two overloaded functions differ only by an optional parameter. As mentioned in the comments, using this is probably a poor design and you should rename the parameters.
As you probably noticed, when you try calling the function in an ordinary way using MyClass().func("A","B"), you get an error message complaining about the ambiguity:
error FS0041: A unique overload for method 'func' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates: member MyClass.func : a:string * ?b:string -> string, member MyClass.func : a:string * b:string -> string
You can call the second overload explicitly in two ways (with or without ?b) thanks to the fact that you can explicitly provide Some value for an optional argument:
MyClass().func("A")
MyClass().func("A",?b=Some "B")
Out of curiosity, it turns out that you can call the first overload via a static member constraint. This is quite ugly and you probably shouldn't be doing this, but it calls the first overload:
let inline callFunc (o:^T) a b =
(^T : (member func : string * string -> string) (o, a, b))
callFunc (MyClass()) "A" "B"

How to implicitly convert to common super types in F# pattern matches?

Problem Summary
At the moment when using f# I must explicitly coerce a value to the parent type of its type in order to get pattern matching expressions to type check correctly. I would ideally like a neater way of doing.
Example
Suppose I have some class hierachy:
type Foo () =
abstract member Value : unit -> string
type A (i:int) =
inherit Foo ()
override this.Value () = i.ToString()
type B (s:string) =
inherit Foo ()
override this.Value () = s
Ideally, and in some programming languages in normally, I would write the equivalent of the following:
let bar (i:int) : Foo =
match i with
| 1 -> B "one"
| _ -> A i
However this fails to type check correctly, giving me the error, "This expression was expected to have type Foo but here has type B". I don't understand why the compiler doesn't have enough information to infer a common super type for the match expression and then check that the common super type is 'Foo'.
At present I am forced to provide an explicit coercion for every case in the pattern match:
let bar2 (i:int) : Foo =
match i with
| 1 -> (B "one") :> Foo
| _ -> (A i) :> Foo
I would like to avoid this.
Further Notes
Intuition suggests that this is a result of a more general issue. I would have thought though that something as common as pattern matching, or if statements which also exhibit the same property, would have a type checking rule to account for common super types.
Before anyone suggests - I appreciate that if A or B were Object Expressions this would work, but my real example is creating instances of C# classes where they are normal classes.
Is there a way for me to declare functions to implicitly convert types, as for example scala has, so I could apply automatic conversions for the module where I'm doing this generation?
Thanks for any help on this matter.
I would use upcast, a la
[<AbstractClass>]
type Foo () =
abstract member Value : unit -> string
type A (i:int) =
inherit Foo ()
override this.Value () = i.ToString()
type B (s) =
inherit Foo ()
override this.Value () = s
let bar2 i : Foo =
match i with
| 1 -> upcast B "one"
| _ -> upcast A i
You still have to add it to every branch, but this is often preferable to casting to the type, since often the typename is like 20 or 30 characters long (MyNamespace.ThisThingy), whereas upcast is just 6 characters.
But, briefly, the language rules don't allow for anything else, the types of all the branches have to be equal.
I've seen this question a couple of times before, but I just realized that there is quite an interesting way to workaround the issue (without any significant negative effects such as big runtime overhead).
You can use a very simple computation expression that has only Return member. The builder will have a type parameter and Return will expect values of this type. The trick is, that F# does insert automatic upcasts when calling a member. Here is the declaration:
type ExprBuilder<'T>() =
member x.Return(v:'T) = v
let expr<'T> = ExprBuilder<'T>()
To write a simple pattern matching that returns anything as obj, you can now write:
let foo a = expr<obj> {
match a with
| 0 -> return System.Random()
| _ -> return "Hello" }
You still have to be explicit about the return type (when creating the computation expression), but I find the syntax quite neat (but it is definitely a tricky use that could confuse people who'll see it for the first time).

How to write function where argument is type but not typed value?

I want to convert a string representations of few dozen enum types to enum values.
It's easy to convert string to concrete type:
Enum.Parse(typeof<FontStyle>,"Bold") |> unbox<FontStyle>
but for now i want to write function where type and string are parameters.
The best one i can write is:
> let s2e (_: 'a) s = Enum.Parse(typeof<'a>,s) |> unbox<'a>;;
val s2e : 'a -> string -> 'a
> s2e FontStyle.Regular "Bold";;
val it : FontStyle = Bold
Is there any option to write something like this but with type itself as first argument?
The function needs to take a single type parameter, which will be the type of the returned enum. However, you don't need to specify the type using a "fake" parameter that isn't used anywhere in the code - you can specify the actual type parameter when calling the function using the same notation as for example when calling defaultof<SomeType>.
The following modified function takes a single type parameter which occurs only in the return type (to avoid confusing SO code formatter, I replaced ' with ´ in the code):
> let parseEnum<´a> s = Enum.Parse(typeof<´a>,s) |> unbox<´a>;;
val parseEnum : string -> ´a
When calling the function, you need to specify the type explicitly:
> parseEnum<FontStyle> "Bold";;
val it : FontStyle = Bold
Your solution was pretty close to this - the only change is that you can specify the type parameter explicitly instead of providing a witness value to guide the type inference.
Tomas's answer is good. Additionally, note that you can apply F#'s enum constraints to prevent nonsensical type parameters from being used:
let parseEnum<'t,'u when 't:enum<'u>> s = System.Enum.Parse(typeof<'t>, s) :?> 't
(parseEnum "Class" : System.AttributeTargets)
Now calling (parseEnum "Test" : int) will fail at compile time since int is not an enum.
EDIT
Since we don't actually do anything with the underlying type 'u, we don't need the full power of F#'s enum constraints, as ssp points out in a comment. This is easier to use because it only has a single type parameter:
let parseEnum<'t when 't :> System.Enum and 't : struct> s =
System.Enum.Parse(typeof<'t>, s) :?> 't
Note that the struct constraint prevents using System.Enum itself as the type argument.

Resources