This type definition works:
type Model<'t,'u when 't :> seq<'u> >(query: unit -> 't) = class end
However, as for me the 'u is redundant here, but next definition:
type Model<'t when 't :> seq<_> >(query: unit -> 't) = class end
produces the error:
Anonymous type variables are not permitted in this declaration - F# Compiler (715)
Compact
The most compact form:
type Model<'t>(query:unit -> #seq<'t>) = class end
during instance creation:
Query.users |> Model
produces error:
Type constraint mismatch. The type unit -> (string * int) list
is not compatible with type unit -> 'a
F# Compiler (193)
Probably, because of described here Why are flexible types not allowed in record type definitions?. But anyway the error description is unclear for me, what is wrong in substituting (string * int) list instead of 'a?
Background
The real type Model is a wrapper for a database query, it implements INotifyPropertyChanged and contains mutable state of type Outcome:
type 't Outcome =
| Empty
| Loading
| Success of 't
| Fault of string * string
The #seq<'t> type constraint is needed to detect Empty case with Seq.isEmpty in generic way due to a query can return seq or list or array
As explained by #kvb, the problem is that you cannot have generic constructors - so you can either introduce a new type parameter to the entire class (as you did in your first example), or the return type of query will need to be just seq<'t> (as the compiler forces you to do in your other examples).
If you want to keep things encapsulated in a class, one nice trick is to make the constructor private and add a static Create method which can have the extra generic parameter that you need:
type Model<'t> private(query:unit -> seq<'t>) =
static member Create(query:unit -> #seq<'t>) =
Model(fun () -> query () :> _)
The problem with the definition
type Model<'t>(query:unit -> #seq<'t>) = class end
is that the # introduces an implicit type parameter, but constructors can't have their own type parameters in addition to the class's. For instance, you also can't define something like this:
type IntConverter(conv:'a -> int) = class end
because the constructor can't have its own free type parameter 'a.
However, the good news is that even if you change your definition to
type Model<'t>(query:unit -> seq<'t>) = class end
it's easy to accept an input of type unit -> #seq<'t>:
let model f = Model(fun () -> upcast f())
I guess as long as you are willing to add that helper function you can get somewhat close:
type Model<'t>(query:unit -> seq<'t>) =
class
static member Unwrap<'s when 's :> seq<'t>> (cpar: unit -> 's) =
cpar >> (fun (s: 's) -> (s :> seq<'t>))
static member New (cpar) =
new Model<'t>(Model.Unwrap<_> cpar)
end
At least that will allow you to use something like (I think)
Query.users |> Model.New
As soon as I do something similar with an actual constructor (overload) the compiler says "The type variable 's has been constrained to be type 'seq<'t>'.". So apparently different rules apply to constructors than to static methods (why do I sound surprised).
Related
In F#, I have defined an interface with a generic member:
type MyType =
abstract MyMember<'a> : 'a -> int
I would like to write a function that can create an object that implements this interface:
module MyType =
let create f =
{
new MyType with
member __.MyMember(x) = f x
}
This currently fails to compile with the following error message:
This code is not sufficiently generic. The type variable 'a could not be generalized because it would escape its scope.
Is it possible to make this work via inlining and static resolved type parameters (or something similar)? Thanks.
An explanation for the compile error:
Object expressions construct anonymous classes - these are just regular classes, with a compiler generated name. You're essentially creating a closure which captures f.
This is how you'd normally implement it:
type MyType =
abstract MyMember<'a> : 'a -> int
type MyNewType (f) =
interface MyType with
member _.MyMember x = f x
The type's constructor would have a parameter f of type 'a -> int, where 'a would normally be decided by the first usage of MyNewType.
But there's no way to generalize f such that it could be captured as a value that would satisfy the generic constraint of MyMember. Here sufficiently generic means a type of one order above the generic type.
I am trying to cast obj to 'T and I receive FS0013 error in compile time.
What is wrong with my code?
Maybe it is broken because I tried to "map" it from C# and this is done in completely different way in F#?
let myFunc (x : Option<'T>) =
match x with
None -> failwith "wtf"
| Some x -> Convert.ChangeType(x, typedefof<'T>) :> 'T
Full error text:
error FS0013: The static coercion from type
obj
to
'T
involves an indeterminate type based on information prior to this program point. Static coercions are not allowed on some types. Further type annotations are needed.
UPDATE:
This is the actual function I am trying to write. Option's value is used in case I don't have my own value.
let ( %? ) (defaultValue : Option<'a>) (parameterName : string)
= match (environVar parameterName) with
null -> match defaultValue with
None -> failwith "No value found as well as default value is not set"
| Some defaultVal -> defaultVal
| x -> let objectResult = Convert.ChangeType(x, typedefof<'a>)
objectResult :> 'a
You don't need to convert !
Just write:
| Some x -> x
Then your function is generic.
The pattern match has already decomposed the type and unwrapped the value from the option.
Don't confuse obj with generic 'T.
A function returning an obj is not necessarily generic.
EDIT
After your update, you can use this:
objectResult :?> 'a
But you will have no run-time guaranties.
In F# :> means 'upcast' and :?> means 'downcast' (if you can). The former has compile-time checking that's why 'cast' is split in 2 different operations.
In F# Interactive (fsi), you can use AddPrinter or AddPrinterTransformer to provide pretty printing for a type in the interactive session. How can I add such a printer for a generic type? Using the wildcard _ for the type doesn't work:
> fsi.AddPrinter(fun (A : MyList<_>) -> A.ToString());;
The printer just isn't used.
Putting in a type parameter also gives a warning:
> fsi.AddPrinter(fun (A : MyList<'T>) -> A.ToString());;
fsi.AddPrinter(fun (A : MyList<'T>) -> A.ToString());;
-------------------------------^^
d:\projects\stdin(70,51): warning FS0064: This construct causes code
to be less generic than indicated by the type annotations. The type
variable 'T been constrained to be type 'obj'.
which is not what I want, either.
This won't work for the general case, but since it appears you're working with your own type (at least in your example), and assuming you don't want to affect ToString, you could do something like this:
type ITransformable =
abstract member BoxedValue : obj
type MyList<'T>(values: seq<'T>) =
interface ITransformable with
member x.BoxedValue = box values
fsi.AddPrintTransformer(fun (x:obj) ->
match x with
| :? ITransformable as t -> t.BoxedValue
| _ -> null)
Output:
> MyList([1;2;3])
val it : MyList<int> = [1; 2; 3]
For a third-party generic type you could use AddPrintTransformer and reflection to get the value to be displayed. An interface is just easier if you have the source.
I am trying to write a typed abstract syntax tree datatype that can represent
function application.
So far I have
type Expr<'a> =
| Constant of 'a
| Application of Expr<'b -> 'a> * Expr<'b> // error: The type parameter 'b' is not defined
I don't think there is a way in F# to write something like 'for all b' on that last line - am I approaching this problem wrongly?
In general, the F# type system is not expressive enough to (directly) define a typed abstract syntax tree as the one in your example. This can be done using generalized algebraic data types (GADTs) which are not supported in F# (although they are available in Haskell and OCaml). It would be nice to have this in F#, but I think it makes the language a bit more complex.
Technically speaking, the compiler is complaining because the type variable 'b is not defined. But of course, if you define it, then you get type Expr<'a, 'b> which has a different meaning.
If you wanted to express this in F#, you'd have to use a workaround based on interfaces (an interface can have generic method, which give you a way to express constraint like exists 'b which you need here). This will probably get very ugly very soon, so I do not think it is a good approach, but it would look something like this:
// Represents an application that returns 'a but consists
// of an argument 'b and a function 'b -> 'a
type IApplication<'a> =
abstract Appl<'b> : Expr<'b -> 'a> * Expr<'b> -> unit
and Expr<'a> =
// Constant just stores a value...
| Constant of 'a
// An application is something that we can call with an
// implementation (handler). The function then calls the
// 'Appl' method of the handler we provide. As this method
// is generic, it will be called with an appropriate type
// argument 'b that represents the type of the argument.
| Application of (IApplication<'a> -> unit)
To represent an expression tree of (fun (n:int) -> string n) 42, you could write something like:
let expr =
Application(fun appl ->
appl.Appl(Constant(fun (n:int) -> string n),
Constant(42)))
A function to evaluate the expression can be written like this:
let rec eval<'T> : Expr<'T> -> 'T = function
| Constant(v) -> v // Just return the constant
| Application(f) ->
// We use a bit of dirty mutable state (to keep types simpler for now)
let res = ref None
// Call the function with a 'handler' that evaluates function application
f { new IApplication<'T> with
member x.Appl<'A>(efunc : Expr<'A -> 'T>, earg : Expr<'A>) =
// Here we get function 'efunc' and argument 'earg'
// The type 'A is the type of the argument (which can be
// anything, depending on the created AST)
let f = eval<'A -> 'T> efunc
let a = eval<'A> earg
res := Some <| (f a) }
res.Value.Value
As I said, this is a bit really extreme workaround, so I do not think it is a good idea to actually use it. I suppose the F# way of doing this would be to use untyped Expr type. Can you write a bit more about the overall goal of your project (perhaps there is another good approach)?
I am trying to write a typed abstract syntax tree datatype that can represent
function application.
So far I have
type Expr<'a> =
| Constant of 'a
| Application of Expr<'b -> 'a> * Expr<'b> // error: The type parameter 'b' is not defined
I don't think there is a way in F# to write something like 'for all b' on that last line - am I approaching this problem wrongly?
In general, the F# type system is not expressive enough to (directly) define a typed abstract syntax tree as the one in your example. This can be done using generalized algebraic data types (GADTs) which are not supported in F# (although they are available in Haskell and OCaml). It would be nice to have this in F#, but I think it makes the language a bit more complex.
Technically speaking, the compiler is complaining because the type variable 'b is not defined. But of course, if you define it, then you get type Expr<'a, 'b> which has a different meaning.
If you wanted to express this in F#, you'd have to use a workaround based on interfaces (an interface can have generic method, which give you a way to express constraint like exists 'b which you need here). This will probably get very ugly very soon, so I do not think it is a good approach, but it would look something like this:
// Represents an application that returns 'a but consists
// of an argument 'b and a function 'b -> 'a
type IApplication<'a> =
abstract Appl<'b> : Expr<'b -> 'a> * Expr<'b> -> unit
and Expr<'a> =
// Constant just stores a value...
| Constant of 'a
// An application is something that we can call with an
// implementation (handler). The function then calls the
// 'Appl' method of the handler we provide. As this method
// is generic, it will be called with an appropriate type
// argument 'b that represents the type of the argument.
| Application of (IApplication<'a> -> unit)
To represent an expression tree of (fun (n:int) -> string n) 42, you could write something like:
let expr =
Application(fun appl ->
appl.Appl(Constant(fun (n:int) -> string n),
Constant(42)))
A function to evaluate the expression can be written like this:
let rec eval<'T> : Expr<'T> -> 'T = function
| Constant(v) -> v // Just return the constant
| Application(f) ->
// We use a bit of dirty mutable state (to keep types simpler for now)
let res = ref None
// Call the function with a 'handler' that evaluates function application
f { new IApplication<'T> with
member x.Appl<'A>(efunc : Expr<'A -> 'T>, earg : Expr<'A>) =
// Here we get function 'efunc' and argument 'earg'
// The type 'A is the type of the argument (which can be
// anything, depending on the created AST)
let f = eval<'A -> 'T> efunc
let a = eval<'A> earg
res := Some <| (f a) }
res.Value.Value
As I said, this is a bit really extreme workaround, so I do not think it is a good idea to actually use it. I suppose the F# way of doing this would be to use untyped Expr type. Can you write a bit more about the overall goal of your project (perhaps there is another good approach)?