F# - 在 curried 函数参数上设置类型注释

标签 f#

let actionOne value =
    sprintf "action one %s" (value.Substring(1))

let actionTwo (value:string) =
    sprintf "action two: %s" (value.Substring(1))


let one = actionOne "one"
let two = actionTwo("two")

如何维护 Curried form并在 actionOne 函数上添加类型注释value:string

[编辑]
MS 文档显示此示例以比较“元组形式”和“柯里化(Currying)形式”:

// Tuple form.
member this.SomeMethod(param1, param2) = ...
// Curried form.
let function1 param1 param2 = ...

我的代码无法编译,因为 value 需要一个 type 注释(因为它与 .Substring() 一起使用)。
我可以添加类型注释,但这会使 ActionOne 签名与 ActionTwo 相同。
这个改变迫使我在我想使用括号时使用它:

如何更改 ActionOne 函数(添加类型注释)并避免更改调用,即:保留没有括号

最佳答案

正如我和 Bui 的评论所建议的那样,actionOneactionTwo 都是柯里化(Currying)形式。但是因为只有一个参数,所以柯里化(Currying)形式和非柯里化(Currying)形式之间没有区别:另一种说法是参数是一个元组,最基本的元组。

如果您有两个或更多参数,它就会变得更相关。当您对参数进行元组时,它是元组形式,如果您不这样做,该函数将是可柯里化(Currying)的。

下面是如何分配或不分配类型注释:

/// curried form
let f x y = printfn "%A, %A" x y
/// tupled argument
let f (x, y) = printfn "%A, %A" x y

/// curried form with type annotations
let f (x: string) (y: string) = printfn "%A, %A" x y
/// tupled argument with type annotations
let f (x: string, y: string) = printfn "%A, %A" x y

/// curried form with type annotations and return type spec
let f (x: string) (y: string): unit = printfn "%A, %A" x y
/// tupled argument with type annotations and return type spec
let f (x: string, y: string): unit = printfn "%A, %A" x y

当我们在 FSI 中一一粘贴这些行时,您可以看到签名更改(最后两行除外,因为返回类型已经被推断为 unit):

> let f x y = printfn "%A, %A" x y;;
val f : x:'a -> y:'b -> unit

> let f (x, y) = printfn "%A, %A" x y;;
val f : x:'a * y:'b -> unit

> let f (x: string) (y: string) = printfn "%A, %A" x y;;
val f : x:string -> y:string -> unit

> let f (x: string, y: string) = printfn "%A, %A" x y;;
val f : x:string * y:string -> unit

> let f (x: string) (y: string): unit = printfn "%A, %A" x y;;
val f : x:string -> y:string -> unit

> let f (x: string, y: string): unit = printfn "%A, %A" x y;;
val f : x:string * y:string -> unit

元组形式的另一种选择是有一个元组参数,这有时会派上用场。你像这样声明它,你可以像调用任何其他带有元组参数的函数一样调用它:或者使用一个已经是元组的变量,或者使用两个元组形式的参数:

// let type inference do the work for you:
> let f x = printfn "%A, %A" (fst x) (snd x);;
val f : 'a * 'b -> unit

// with specific type
> let f (x: string * string) = printfn "%A, %A" (fst x) (snd x);;
val f : string * string -> unit

在您的问题中回复您的编辑:

I can add the type annotation, but that makes ActionOne signature identical to ActionTwo. This change FORCE me to use the parenthesis when I want to use it:

parens 的使用似乎有些困惑。 MS 文档给出的示例建议“没有括号意味着没有元组”。这并不完全正确:

// no parens, curried
let f a b = a + b
let x = f 42 43

// with parens, this is identical and still curried
let f (a) (b) = a + b
let x = f (42) (43)

// with parens in other places, still identical, except for the type
let f (a) (b) = (a: int64) + (b: int64)
let x = f (42L: int64) (43L)

MS 文档显示括号的原因是您不能编写 f x, y = x + y。在这种情况下,您必须使用括号。在 F# 的几乎所有情况下,这都与具有最高优先级的空格字符有关。逗号最低。因此,您必须给出括号以告诉编译器您希望参数被元组化:f (x, y) = x + y

在单参数函数的情况下,您需要带有类型注释的括号,否则您将指定返回类型。所以 f x: int = x + 12 是指定返回类型的函数,而 f (x: int) = x + 12 是指定返回类型的函数参数类型x

关于F# - 在 curried 函数参数上设置类型注释,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62245513/

相关文章:

dataframe - 如何在 FSI 中将 Deedle DataFrame 显示为漂亮的表格?

F#如何将类型添加到列表中?

c# - 使用 WCF 和 C# (F#) 收集类似散点的操作

class - 是否应该包装类型提供程序包含在类中具有副作用的值?

asynchronous - 在 F# 中,如何在没有可变集合的异步计算中创建 Async<unit> 列表?

debugging - 如何在llvm源代码级调试信息中表示函数式语言调试信息?

javascript - 如何与 WebSharper 交互和设置 DOM 属性?

f# - 如果它崩溃,如何重新启动异步 Suave 服务器?

visual-studio - 如何在 Visual Studio 2017 版本 15.3 中使用 F#?

f# - 同名的模块和类