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函数(添加类型注释)并避免改变调用,即:剩余的 无括号 ?
正如我和Bui的评论所建议的,这两个 actionOne
和 actionTwo
是卷曲形式的。但由于只有一个参数,所以没有咖哩形式和非咖哩形式之分:另一种说法是,参数是一个一元组,是最基本的元组。
如果你有两个参数或更多参数,那就更有意义了。当你把参数元组化的时候,它是元组形式的,当你不元组化的时候,函数将是可卷曲的。
下面是如何分配,或者不分配类型注释。
/// 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
.