Reputation: 493
I want create an instance of Person. Person is a type of Animal. When I try to create a Person, the IDE says me "This expression was expected to have type 'Person', but here has type 'Animal'".
type Person(name) =
member this.Name: string = name
type Animal =
| Person of Person
| Cat
| Dog
let person: Person = Person(name = "John")
Upvotes: 1
Views: 87
Reputation: 571
In F# names acts as bindings to types and values and at any time you can redefine what a name "points" to. E.g.
// lets define type A
type A(name) = member this.Name : string = name
let x = A("test")
// lets "bind" the type name 'A' to a new type
type A(number) = member this.Number : int = number
let y = A(10)
printfn "type name of x: %s" (x.GetType().Name) // prints 'type name of x: A'
printfn "type name of y: %s" (y.GetType().Name) // prints 'type name of y: A'
So x
and y
are both of a type named A
, but not the same. The same logic applies to Person
and Animal.Person
, and dependent on the order you define them in, the last defined will be the one referenced when typing Person
.
As mentioned, you can use new or definition order to access both. You could also decide to put the Person
class in a different module than Animal
.
module Inner =
type Person(name) ...
This way you can access your types by prepending the module name.
Upvotes: 1
Reputation: 26184
The problem is that Person
refers to both the type and the case of the Discriminated union.
You can invert the definitions so it will resolve to the last one:
type Animal =
| Person of Person
| Cat
| Dog
and
Person (name) =
member this.Name: string = name
let person: Person = Person(name = "John")
// then to create an animal
let animal = Animal.Person (Person(name = "John"))
Alternatives solutions are to use new
keyword as @MarcinJuraszek suggested in the comments or considering a different name for the DU case and the type.
Upvotes: 1