【问题标题】:how do i create a computational expression that takes parameters?如何创建带参数的计算表达式?
【发布时间】:2011-05-13 18:28:49
【问题描述】:

我想创建几个计算表达式,用于访问数据库并返回一个类似这样的项目列表(我在代码 cmets 中也有问题):

let foo x y z = proc "foo" {
    let! cmd = proc.CreateCommand() // can I do this?
    do! In "x" DbType.Int32 // would i gain anything by replacing DbType with a union 
                            // type since the names would match actual data types?
    do! In "y" DbType.String 15;
    cmd?x <- x
    cmd?y <- y
    use! r = cmd.ExecuteReader() // would this be bad form for creating a workflow builder?
    return! r {
        let item = MyItem()
        do! item.a <- r.GetInt32("a")
        do! item.a <- r.GetString("b")
        do! item.c <- r.GetDateTime("c")
        yield! item
    }
}

如何创建一个工作流构建器,使其实例接受参数?

let proc name = ProcedureBuilder(connStr, factory) // how do I do this?

【问题讨论】:

标签: f# monads


【解决方案1】:

是的,您可以这样做。您可以在具有静态已知类型的任何表达式之后使用计算表达式语法以公开正确的方法。所以下面的代码可以工作(但没有做任何特别有趣的事情):

let f x = async
let v = f "test" { return 1 }

这里,f 的类型为'a -&gt; AsyncBuilder,因此f "test" 的类型为AsyncBuilder,并且可以跟在计算表达式语法之后。您的let proc name = ProcedureBuilder(connStr, factory) 示例非常好,假设ProcedureBuilder 定义正确,但您可能希望name 出现在构造函数参数的某个位置。

【讨论】:

  • 这整个咖喱的东西仍然让我措手不及。感谢您的出色解释。以确保我完全理解。因为我有 proc 的参数,而不是 let proc = ProcedureBuilder() 程序构建器在我调用函数之前不会被执行,如果没有参数,代码就会被执行并必须立即处理。前者每次都会获得一个新实例,而后者一遍又一遍地是同一个实例。对吗?
【解决方案2】:

Keith (kvb) 的答案是正确的 - 您可以使用参数化计算构建器。计算表达式的语法是:

<expr> { <cexpr> }

因此,构建器可以由任何表达式创建。通常,它是一些值(例如async),但它可以是函数调用,甚至可以是构造函数调用。使用它时,您通常会定义一个参数化构建器,然后使用函数将参数传递给构造器(正如@kvb 建议的那样)。

实际上我在不久前写了一个这样的例子,所以我可以分享一个例子——我认为——这是非常有用的。你可以在 F# sn-ps 上找到它:http://fssnip.net/4z

该示例为 ASP.NET MVC 创建了一个“特殊”异步计算构建器,其行为与标准 async 类似。唯一的区别是它添加了Run 成员,该成员使用AsyncManager(由ASP.NET 提供)来执行工作流。

以下是 sn-p 中的一些相关部分:

/// A computation builder that is almost the same as stnadard F# 'async'.
/// The differnece is that it takes an ASP.NET MVC 'AsyncManager' as an
/// argumnet and implements 'Run' opration, so that the workflow is 
/// automatically executed after it is created (using the AsyncManager)
type AsyncActionBuilder(asyncMgr:Async.AsyncManager) = 
  // (Omitted: Lots of boilerplate code)

  /// Run the workflow automatically using ASP.NET AsyncManager
  member x.Run(workflow) = 
    // Use 'asyncMgr' to execute the 'workflow'

sn-p 将构造包装在一个基类中,但您可以定义一个函数:

let asyncAction mgr = new AsyncActionBuilder(mgr)

然后用它在 ASP.NET MVC 中定义异步动作:

member x.LengthAsync(url:string) = asyncAction x.AsyncManager {
    let wc = new WebClient()
    let! html = wc.AsyncDownloadString(url)
    return html.Length }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多