类型定义中的顺序约束
Seq constraint in type definition
此类型定义有效:
type Model<'t,'u when 't :> seq<'u> >(query: unit -> 't) = class end
然而,对我来说'u
在这里是多余的,但是下一个定义:
type Model<'t when 't :> seq<_> >(query: unit -> 't) = class end
产生错误:
Anonymous type variables are not permitted in this declaration - F# Compiler (715)
紧凑
最紧凑的形式:
type Model<'t>(query:unit -> #seq<'t>) = class end
实例创建期间:
Query.users |> Model
产生错误:
Type constraint mismatch. The type unit -> (string * int) list
is not compatible with type unit -> 'a
F# Compiler (193)
可能是因为此处描述的缘故 。但无论如何,我不清楚错误描述,用 (string * int) list
代替 'a
有什么问题?
背景
真实类型 Model
是数据库查询的包装器,它实现 INotifyPropertyChanged
并包含 mutable
类型 Outcome
:
的状态
type 't Outcome =
| Empty
| Loading
| Success of 't
| Fault of string * string
需要 #seq<'t>
类型约束以通用方式检测 Empty
情况 Seq.isEmpty
由于查询可以 return seq
或 list
或 array
定义有问题
type Model<'t>(query:unit -> #seq<'t>) = class end
是#
引入了隐式类型参数,但是构造函数除了class之外不能有自己的类型参数。例如,您也不能这样定义:
type IntConverter(conv:'a -> int) = class end
因为构造函数不能有自己的自由类型参数'a
.
不过,好消息是,即使您将定义更改为
type Model<'t>(query:unit -> seq<'t>) = class end
很容易接受 unit -> #seq<'t>
:
类型的输入
let model f = Model(fun () -> upcast f())
我想只要你愿意添加那个辅助函数你就可以接近:
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
至少你可以使用类似(我认为)
Query.users |> Model.New
一旦我对实际的构造函数(重载)做了类似的事情,编译器就会说 "The type variable 's
has been constrained to be type 'seq<'t>
'."。因此,显然不同的规则适用于构造函数而不是静态方法(为什么我听起来很惊讶)。
正如@kvb 所解释的那样,问题在于您不能拥有泛型构造函数 - 因此您可以为整个 class 引入一个新的类型参数(就像您在第一个示例中所做的那样),或者return 类型的 query
需要只是 seq<'t>
(编译器强制您在其他示例中这样做)。
如果您想将内容封装在 class 中,一个不错的技巧是将构造函数设为私有并添加一个静态 Create
方法,该方法可以具有您需要的额外通用参数:
type Model<'t> private(query:unit -> seq<'t>) =
static member Create(query:unit -> #seq<'t>) =
Model(fun () -> query () :> _)
此类型定义有效:
type Model<'t,'u when 't :> seq<'u> >(query: unit -> 't) = class end
然而,对我来说'u
在这里是多余的,但是下一个定义:
type Model<'t when 't :> seq<_> >(query: unit -> 't) = class end
产生错误:
Anonymous type variables are not permitted in this declaration -
F# Compiler (715)
紧凑
最紧凑的形式:
type Model<'t>(query:unit -> #seq<'t>) = class end
实例创建期间:
Query.users |> Model
产生错误:
Type constraint mismatch. The type
unit -> (string * int) list
is not compatible with typeunit -> 'a
F# Compiler (193)
可能是因为此处描述的缘故 (string * int) list
代替 'a
有什么问题?
背景
真实类型 Model
是数据库查询的包装器,它实现 INotifyPropertyChanged
并包含 mutable
类型 Outcome
:
type 't Outcome =
| Empty
| Loading
| Success of 't
| Fault of string * string
需要 #seq<'t>
类型约束以通用方式检测 Empty
情况 Seq.isEmpty
由于查询可以 return seq
或 list
或 array
定义有问题
type Model<'t>(query:unit -> #seq<'t>) = class end
是#
引入了隐式类型参数,但是构造函数除了class之外不能有自己的类型参数。例如,您也不能这样定义:
type IntConverter(conv:'a -> int) = class end
因为构造函数不能有自己的自由类型参数'a
.
不过,好消息是,即使您将定义更改为
type Model<'t>(query:unit -> seq<'t>) = class end
很容易接受 unit -> #seq<'t>
:
let model f = Model(fun () -> upcast f())
我想只要你愿意添加那个辅助函数你就可以接近:
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
至少你可以使用类似(我认为)
Query.users |> Model.New
一旦我对实际的构造函数(重载)做了类似的事情,编译器就会说 "The type variable 's
has been constrained to be type 'seq<'t>
'."。因此,显然不同的规则适用于构造函数而不是静态方法(为什么我听起来很惊讶)。
正如@kvb 所解释的那样,问题在于您不能拥有泛型构造函数 - 因此您可以为整个 class 引入一个新的类型参数(就像您在第一个示例中所做的那样),或者return 类型的 query
需要只是 seq<'t>
(编译器强制您在其他示例中这样做)。
如果您想将内容封装在 class 中,一个不错的技巧是将构造函数设为私有并添加一个静态 Create
方法,该方法可以具有您需要的额外通用参数:
type Model<'t> private(query:unit -> seq<'t>) =
static member Create(query:unit -> #seq<'t>) =
Model(fun () -> query () :> _)