Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Seq constraint in type definition

Tags:

f#

seq

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

like image 308
Brains Avatar asked Dec 17 '22 15:12

Brains


1 Answers

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 () :> _)
like image 148
Tomas Petricek Avatar answered Dec 30 '22 02:12

Tomas Petricek