首页 > 解决方案 > 将值传递给管道中的第二个参数

问题描述

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

例如

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

在上面的代码PostAsync中,有 2 个参数,要发布到的 url 和要发布的内容。也尝试过背管和括号,但不知道该怎么做

有任何想法吗?

标签: f#pipeline

解决方案


PostAsync有非柯里化参数,不能一一传入,必须一次性全部传入。这就是为什么你应该总是让你的参数柯里化。

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

选项 1:使用 lambda 表达式:

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

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

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函数,依此类推。


推荐阅读