Compile error when another secondary constructor is added - f#

I have the following type
type NumberedCollection(list) =
let list = list
new () = NumberedCollection(ResizeArray<string>())
It works good as a jellybean for a sweet tooth
But when I add another constructor that takes seq<string>
type NumberedCollection(list) =
let list = list
new () = NumberedCollection(ResizeArray<string>())
new (col :seq<string>) = NumberedCollection(col.ToList())
I get the following compile error
A unique overload for method 'NumberedCollection' could not be determined based on type information prior to this program point. A type annotation may be needed. Candidates are: new : col:seq -> NumberedCollection, new : list:`a -> NumberedCollection
But when I specify type information in primary constructor as List, it works.
My question is, in both versions of secondary constructors, the types provided when invoking the primary is List. Why it has inference issues there ? There is no ambiguity that I can see.

The problem is that, for the first secondary constructor, the compiler doesn't know whether you want to use the second secondary constructor or the primary constructor. The compiler defers determining the type of list in the primary constructor until it knows which places are calling it, and since ResizeArray<string> could be a seq<string> it's ambiguous as to which constructor to call for the first secondary constructor. Notice that in the error message, the type of the parameter to the primary constructor is not defined `a -> NumberedCollection.

Related

Elmish.WPF type conflict: unit -> Model expected where Model provided?

My Elmish.WPF app combines the Elmish.WPF Sample projects ‘NewWindow’ + ‘NewWindow.Core’ which I am adding to a copy of ‘FileDialogsCmdMsg’ + ‘FileDialogsCmdMsg.Core’.
FileDialogsCmdMsg is the basis of this effort and provides the background processing features to which I am adding the ‘NewWindow’ popup window features.
I am stuck on two (2) type-conflicts when WpfProgram.mkProgramWithCmdMsg is called...
...errors on update and bindings calls.
The compiler reports that line has the following errors (see red underlines above)...
...saying that WpfProgram.mkProgramWithCmdMsg expects a unit -> Model but was given a Model where update and bindings are called in the larger type specification.
But here is the type information for the calling function, WpfProgram.mkProgramWithCmdMsg accepting these parameters…
... sorry that is so large.
As you can see, both ‘update’ and ‘bindings’ are producing the Model parameter types expected by WpfProgram.mdProgramWithCmdMsg. And yet we have a unit->Model expected where a Model has been provided type-conflict; why?
Here is more detail on the update type-conflict…
... see how here how here it is claimed a unit->Model is expected when previously you see that update is supposed to expect a Model? Why?
You see the same problem in this detail on the type-conflict with ‘bindings’...
..again showing unit-Model' expected when the correct Model` type parameter is passed.
Here the type information where update is defined…
...and here is the bindings type info…
QUESTION: Why is a "unit->Model expected error reported when the receiving function, WpfProgram.mkProgramWithCmdMsg, and both parameters, update and bindings both respectively provide Model parameters?
Please ask if more detail is needed to get to the bottom of this.
Thanks for your help!
I suspect the problem is with your init function, which (I'm guessing) is a function of type unit -> Model. If this is true, the lambda fun _ -> init, [] binds the concrete type unit -> Model to the 'model type variable. As result, update and bindings also expect the same concrete type, leading to the error message you're seeing.
If I'm correct, you have two choices:
Change init so it is a value of type Model, rather than a function.
Change init so it also returns an empty message list, and then pass init directly to mkProgramWithCmdMsg, rather than passing a lambda.
Note that when you hover over mkProgramWithCmdMsg, the compiler shows you that 'model is indeed bound to unit -> Model, presumably due to the init type mismatch:

How do I create a type that hosts a list of items, that implement an interface, but have different typed parameters?

How do I create a type that hosts a list of items, that implement an interface, but have different typed parameters?
Specifically, I need a container to hold a list of interfaces that have typed parameters that vary.
Note:
The types are not predetermined. Thus, I don't think I can use discriminated unions for generic type parameters that I can't foresee.
Is it possible?
let syncItem1 = { someSyncItem1 with Subscribers = seq {someResponder1} }
let syncItem2 = { someSyncItem2 with Subscribers = seq {someResponder2} }
let engines = seq [Engine(seq {syncItem1}) :> IEngine<int,string>
Engine(seq {syncItem2}) :> IEngine<string,int> // Compile error
] |> MultiEngine
Error:
All elements of a list must be of the same type as the first element, which here is 'string'. This element has type 'int'.
Appendix:
GitHub
You don't. IEngine<int, string> and IEngine<string, int> are, on a type-theoretical level, completely unrelated types and putting them in the same list makes no sense.
If there is a reasonable way that an engine can be used regardless of its parameters, extract that functionality into a parameterless superinterface and make the list typed to that.
If there is no reasonable way to do that, you can't do polymorphic dispatch anyway, so you need type tests and might as well use a list of Object too.

Type name as identifier in F#

I just started to study F# and accidentally wrote this binding
let List = 1
Now when I try to obtain List methods such as 'filter' I get this error
error FS0039: The field, constructor or member 'filter' is not defined.
Of course using method with full type name like Microsoft.FSharp.Collections.List.filter is still working.
I'm wondering why it is possible to use type name as identifier in F# and how I can set back name List to type List from Microsoft.FSharp.Collections.
When I tried to reassign like this
type List = Microsoft.FSharp.Collections.List<'T>
I get
Error FS0039: The type parameter 'T is not defined.
Thank you!
In F# you can redefine almost everything and shadow existing definitions. This applies to both types (well actually types have a different behavior regarding shadowing, they shadow their values as you open the namespaces) and values but not interchangeably since values and type (and also modules) can somehow coexist at the same time in the scope. The compiler will do his best to find out which one is.
You are not forced to, but it's a common good practice in F# not to use let bindings in uppercase.
Regarding your second question, you are using a type parameter in the right side which doesn't exist in the left side of the assignment, it should be:
type List<'T> = Microsoft.FSharp.Collections.List<'T>
But notice that filter doesn't belong to the type. It's rather defined in the List module.
You should just rename your let binding from List to something sensible - as Gustavo mentioned, your definition is shadowing the core List module from F# and there is no way to use List to refer both to your integer and to the module. Shadowing core functions will make your code pretty confusing. It's also a good idea to use camelCase for let bindings, but that's a matter of taste.
If you insist on shadowing List, then you won't be able to call List.filter using List.filter. If you wanted something shorter, you could define module alias:
module FsList = Microsoft.FSharp.Collections.List
Note that your attempt to do something similar with List<'T> does not do the same thing, because functions such as filter are in a module named List rather than being static members of the type. With this, you can call filter using FsList.filter.

Getting FS0035 => Construct is deprecated

In a fsyacc based project, I have this line:
type 'a cucomment = string
This is the full error description I'm getting:
CALast.fs(117,9): error FS0035: This construct is deprecated: This
type abbreviation has one or more declared type parameters that do not
appear in the type being abbreviated. Type abbreviations must use all
declared type parameters in the type being abbreviated. Consider
removing one or more type parameters, or use a concrete type
definition that wraps an underlying type, such as 'type C<'a> = C of
...'.
Any idea how to solve this?
F# no longer allows type aliases that add generic type parameters to a type without declaring a new type. If you want to define a generic type that wraps some other type, you have to use some constructor. For example, you can use single-case discriminated union:
type 'a Cucomment = CC of string
Unfortunately, this means that you'd have to change all code that uses the type to unwrap the value using pattern matching or by adding Value member to the type.
The only case where generic type aliases are allowed is when you declare a version of type with units of measure, which requires a special attribute. However, this is probably not going to work for you (because units behave quite differently):
[<MeasureAnnotatedAbbreviation>]
type 'a Cucomment = string
If this is in some code generated by fsyacc, then that's a bug in fsyacc that should be fixed (I think this was quite recent change). In that case, report it to fsbugs at microsoft dot com.

Unknown need for type annotation or cast

I know I must be missing something really obvious here. B.GetInstance().Call() generates the error: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
I'm using v1.9.9.9.
type A() =
member x.Call() = B.GetInstance().Call()
and B() =
static member GetInstance() = new B()
member x.Call() = ()
I just discovered that this works: (B.GetInstance() :> B).Call()
Any idea why the cast is necessary?
Frequently when you've got a recursive set of methods whose types to infer, F# needs help. A more pleasant alternative would be to annotate the definition of B.GetInstance:
type A() =
member x.Call() = B.GetInstance().Call()
and B() =
static member GetInstance() : B = new B()
member x.Call() = ()
I believe that the reason you run into this problem is that F# tries to solve all inferred types on all methods in A and B simultaneously (because they are defined as mutually recursive types), and this leads to problems, but perhaps someone from the F# team will weigh in.
The quick summary is that in a recursive group (e.g. members in one type, or members of recursive types like we have here) F# reads the declarations in left-to-right top-to-bottom order, followed by the definitions in left-to-right top-to-bottom order. So in this instance when it reaches the definition of A.Call, it has not yet read the definition of B.GetInstance and therefore does not (yet!) know that the return type of GetInstance will be B.
Keith's answer nails it for this situation, you can provide a type annotation to specify the return type of GetInstance in its declaration.
See
Forcing F# type inference on generics and interfaces to stay loose
for a deep discussion of what's going on here.
Note also that in your original attempt, you don't need to "cast" (the potentially dynamic operation, using :>), instead you can just "annotate" (statically declare a type, using :) to get it to compile. But makes more sense to put the type annotation in the method declaration for GetInstance (generally, prefer addition annotations to method signatures instead of arbitrary places inside bodies).

Resources