F# - 为函数参数设置类型注解。

问题描述 投票:0回答:1
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")

如何维护 咖喱形式 并添加 注释类型, value:string关于 动作一 函数?

编辑]MS文档显示这个例子可以比较 "元组形式 "和 "卷曲形式"。

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

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

我怎样才能改变ActionOne函数(添加类型注释)并避免改变调用,即:剩余的 无括号 ?

f#
1个回答
1
投票

正如我和Bui的评论所建议的,这两个 actionOneactionTwo 是卷曲形式的。但由于只有一个参数,所以没有咖哩形式和非咖哩形式之分:另一种说法是,参数是一个一元组,是最基本的元组。

如果你有两个参数或更多参数,那就更有意义了。当你把参数元组化的时候,它是元组形式的,当你不元组化的时候,函数将是可卷曲的。

下面是如何分配,或者不分配类型注释。

/// 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

另一种tupled形式的方法是使用一个单一的参数作为元组,这有时会很方便。你像这样声明它,你可以像其他接受tuple参数的函数一样调用它:或者用一个已经是tuple的变量,或者用tuple形式的两个参数。

// 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

回应你在Q中的编辑:

我可以添加类型注解,但这使得ActionOne和ActionTwo的签名相同。这个改动让我在想使用括号的时候不得不使用。

似乎对小括号的使用有一些困惑。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文档中之所以显示出parens,是因为你不能写出... f x, y = x + y. 在这种情况下,你 必须 使用parens。这与F#中几乎所有情况下空格字符的优先级最高有关。而逗号的优先级最低。因此,您 必须 用括号告诉编译器,你希望参数是tupled的。f (x, y) = x + y.

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

© www.soinside.com 2019 - 2024. All rights reserved.