F# 如何修复由使用自定义工作流生成器的计算表达式生成的这些错误?
从文档中我了解到,如果Run被实现,它将在计算表达式的末尾被自动调用。它说:F# 如何修复由使用自定义工作流生成器的计算表达式生成的这些错误?,f#,computation-expression,F#,Computation Expression,从文档中我了解到,如果Run被实现,它将在计算表达式的末尾被自动调用。它说: builder.Run(builder.Delay(fun () -> {| cexpr |})) 将为计算表达式生成。如果工作流生成器中未定义运行和/或延迟,则将忽略它们。我希望我的ReaderBuilder在自动调用Run时返回MyItem对象的列表。所以我不明白为什么会出现类型不匹配错误。错误是由我在这里列出的代码末尾的ProcedureBuilder foo中的return语句生成的。有人能解释一下我对
builder.Run(builder.Delay(fun () -> {| cexpr |}))
将为计算表达式生成。如果工作流生成器中未定义运行和/或延迟,则将忽略它们。我希望我的ReaderBuilder在自动调用Run时返回MyItem对象的列表。所以我不明白为什么会出现类型不匹配错误。错误是由我在这里列出的代码末尾的ProcedureBuilder foo中的return语句生成的。有人能解释一下我对工作流构建器的误解以及我的错误实现吗
我得到以下错误:
类型“a列表”与类型“ReaderBuilder”不兼容
open System
open System.Data
open System.Data.Common
open System.Configuration
let config = ConfigurationManager.ConnectionStrings.Item("db")
let factory = DbProviderFactories.GetFactory(config.ProviderName)
type Direction =
| In
| Out
| Ref
| Return
type dbType =
| Int32
| String of int
type ReaderBuilder(cmd) =
let mutable items = []
member x.Foo = 2
member x.YieldFrom item =
items <- item::items
item
member x.Run item =
items
type ProcBuilder(procedureName:string) =
let name = procedureName
let mutable parameters = []
let mutable cmd:DbCommand = null
let mutable data = []
member x.Command with get() = cmd
member x.CreateCommand() =
factory.CreateCommand()
member x.AddParameter(p:string*dbType*Direction) =
parameters <- p::parameters
member x.Bind(v,f) =
f v
member x.Reader = ReaderBuilder(cmd)
member x.Return(rBuilder:ReaderBuilder) =
data
let (?<-) (builder:ProcBuilder) (prop:string) (value:'t) =
builder.Command.Parameters.[prop].Value <- value
type MyItem() =
let mutable _a = 0
let mutable _b = String.Empty
let mutable _c = DateTime.Now
member x.a
with get() = _a
and set n = _a <- n
member x.b
with get() = _b
and set n = _b <- n
member x.c
with get() = _c
and set n = _c <- n
let proc name = ProcBuilder(name)
let (%) (builder:ProcBuilder) (p:string*dbType*Direction) =
builder.AddParameter(p)
builder
let (?) (r:DbDataReader) (s:string) = r.GetOrdinal(s)
let foo x y =
let foo = proc "foo" % ("x", Int32, In) % ("y", String(15), In)
foo?x <- x
foo?y <- y
foo {
do! foo?x <- x
do! foo?y <- y
return foo.Reader {
let item = MyItem()
item.a <- r.GetInt32("a")
item.b <- r.GetString("b")
item.c <- r.GetDateTime("c")
yield! item
}
}
类型约束不匹配。类型“a列表”与类型ReaderBuilder不兼容类型“a列表”与类型“ReaderBuilder”不兼容
open System
open System.Data
open System.Data.Common
open System.Configuration
let config = ConfigurationManager.ConnectionStrings.Item("db")
let factory = DbProviderFactories.GetFactory(config.ProviderName)
type Direction =
| In
| Out
| Ref
| Return
type dbType =
| Int32
| String of int
type ReaderBuilder(cmd) =
let mutable items = []
member x.Foo = 2
member x.YieldFrom item =
items <- item::items
item
member x.Run item =
items
type ProcBuilder(procedureName:string) =
let name = procedureName
let mutable parameters = []
let mutable cmd:DbCommand = null
let mutable data = []
member x.Command with get() = cmd
member x.CreateCommand() =
factory.CreateCommand()
member x.AddParameter(p:string*dbType*Direction) =
parameters <- p::parameters
member x.Bind(v,f) =
f v
member x.Reader = ReaderBuilder(cmd)
member x.Return(rBuilder:ReaderBuilder) =
data
let (?<-) (builder:ProcBuilder) (prop:string) (value:'t) =
builder.Command.Parameters.[prop].Value <- value
type MyItem() =
let mutable _a = 0
let mutable _b = String.Empty
let mutable _c = DateTime.Now
member x.a
with get() = _a
and set n = _a <- n
member x.b
with get() = _b
and set n = _b <- n
member x.c
with get() = _c
and set n = _c <- n
let proc name = ProcBuilder(name)
let (%) (builder:ProcBuilder) (p:string*dbType*Direction) =
builder.AddParameter(p)
builder
let (?) (r:DbDataReader) (s:string) = r.GetOrdinal(s)
let foo x y =
let foo = proc "foo" % ("x", Int32, In) % ("y", String(15), In)
foo?x <- x
foo?y <- y
foo {
do! foo?x <- x
do! foo?y <- y
return foo.Reader {
let item = MyItem()
item.a <- r.GetInt32("a")
item.b <- r.GetString("b")
item.c <- r.GetDateTime("c")
yield! item
}
}
开放系统
开放系统.数据
开放系统.Data.Common
开放系统配置
让config=ConfigurationManager.ConnectionString.Item(“db”)
let factory=dbProviderFactorys.GetFactory(config.ProviderName)
类型方向=
|在
|出去
|参考号
|返回
类型dbType=
|Int32
|整型字符串
类型ReaderBuilder(cmd)=
让可变项=[]
成员x.Foo=2
成员x.YieldFrom项目=
items示例中的问题是foo.Reader{…}
块有一个返回类型MyItem list
(因为这是ReaderBuilder
类型的Run
成员返回的)。但是,ProcBuilder
的Return
成员需要类型为ReaderBuilder
的参数
ReaderBuilder
的data
字段将始终是一个空列表,因此这也是可疑的。我想您可能想更改ProcBuilder
的返回值
,改为使用参数MyItem list
然而,我认为使用自定义计算生成器进行数据库访问并没有给您带来多少好处。从某种意义上讲,您并不是在创建“非标准计算”。相反,您可能只需要一个好的语法来调用命令和读取数据。使用动态操作符可以使它变得非常优雅,即使没有计算构建器——我不久前写过一篇文章 我知道名单将是空的。还有很多其他缺失的部分。我只是想让它达到编译的目的。我将在编译后添加所有实现。我理解你所说的,但我认为我需要一点时间来找出解决这个问题的最佳方法。你可能是对的,这不是计算表达式的最佳用途,但我确实学到了很多:)顺便说一句:计算生成器通常没有任何私有状态。尝试将其设计为不需要私有(可变)状态是一个很好的练习,它可以帮助您理解计算构建器应该如何工作,也有助于找出最佳设计是什么。通常,您应该首先设计由计算生成器创建的“类型”。我在我的书的第12章中写到了这一点。这一章是免费提供的:我的亚马逊愿望清单上已经有这本书了。希望我能在六月份有钱买它。能够从具有你知识水平的人那里得到建议真是太好了。我很感激。