将值传递给管道中的第二个参数

时间:2019-04-13 13:18:46

标签: f# pipeline

在管道中将值传递给函数的第二个参数的正确方法是什么?

例如

async {
    let! response =
        someData
        |> JsonConvert.SerializeObject
        |> fun x -> new StringContent(x)
        |> httpClient.PostAsync "/DoSomething"
        |> Async.AwaitTask
}

上面的代码PostAsync中的

具有两个参数,即要发布到的URL和要发布的内容。也尝试过后管和括号,但不能完全弄清楚该怎么做

有什么想法吗?

2 个答案:

答案 0 :(得分:5)

PostAsync具有非咖喱参数,它们不能一一传递,必须一次全部传递。这就是为什么您应该始终对参数进行管理的原因。

但是可惜,您无法控制PostAsync的定义,因为它是.NET库方法,因此您必须以一种或另一种方式包装它。有几种选择:

选项1 :使用Lambda表达式:

|> fun body -> httpClient.PostAsync( "/DoSomething", body )

选项2 :为自己声明一个带有咖喱参数的函数

let postAsync client url body = 
    client.PostAsync(url, body)

...

|> postAsync httpClient "/DoSomething"

这通常是我的首选选项:在使用.NET API之前,我总是将它们包装为F#形式。这样做更好,因为同一个包装器不仅可以转换参数,还可以转换其他东西,例如错误处理或您的情况下的异步模型:

let postAsync client url body = 
    client.PostAsync(url, body) 
    |> Async.AwaitTask

选项3 :超级通用,使自己成为将任何功能从非咖喱转换为咖喱的功能。在其他功能语言中,此类功能通常称为uncurry

let uncurry f a b = f (a, b)

...

|> uncurry httpClient.PostAsync "/DoSomething"

一个问题是它仅适用于两个参数。如果您有一个带有三个参数的非咖喱函数,则必须为其创建一个单独的uncurry3函数,依此类推。

答案 1 :(得分:3)

在F#中,您经常需要使用.NET API,这些API不能很好地用作功能管道。在这种情况下,您可以做各种技巧以使其适合(通常非常丑陋)管道,或者可以使用F#是多范式这一事实,并以更加面向对象的风格编写代码。

在您的示例中,我将使用更多类似于C#的样式,因为代码不是非常友好的管道:

async {
    let serialized = JsonConvert.SerializeObject(someData)
    let postData = new StringContent(serialized)
    let! response = httpClient.PostAsync("/DoSomething", postData) |> Async.AwaitTask
}

我认为这也不应该是管道也有很好的理论上的理由-通常,如果您具有要通过一系列操作进行转换的“主要实体”,则管道可以很好地工作。通常可以是某些通用类型,例如list<'a>或非通用类型,例如Chart

在您的示例中,您从对象开始,将其转换为JSON,然后将其转换为StringContent,然后转换为Task<'T>等。换句话说,它不是在转换实体-只是在做一个很多无关的东西。在这种情况下,我宁愿使用更明确的编码样式,而不是管道。