我正在尝试制作一个将字符串和整数作为参数/输入的函数。
let rec twoTwo (s : string) (n : int) =
match n with
|0 -> 0
|_ -> s + (twoTwo s (n-1))
printfn "%A" (twoTwo "string" 5)
在这里,我得到一个错误,即类型为int与类型字符串不匹配。超越我为什么?它是在递归调用中错误键入不匹配的。
怎么了?
这是一个要考虑的问题:函数返回什么?
如果查看的第一个分支,则match
返回int
,但是在第二个分支中,您将自己的返回值与一起使用string
,因此返回值必须为字符串。
那是什么呢?编译器无法分辨您的意思,因此抱怨。
回应您的评论:
编译器首先在第一个分支中读取零,然后在此基础上确定函数的返回必须为int
。之后,编译器遇到了字符串连接,发现已经确定的返回类型不合适,并发出了错误。
如果分支反向,则逻辑也将反向:编译器将首先遇到串联,并在此基础上确定返回类型必须为string
。在那之后,它将遇到零,看到它与先前确定的返回类型不匹配,并抱怨。在这种情况下,错误将为零。
在这种情况下,您会抱怨吗?为什么?您如何期望编译器知道错误为零,而不是串联?编译器可能只知道两个分支不匹配。它不知道哪个是正确的。
您认为这很明显,因为您知道自己打算做什么。但是编译器不知道您打算做什么,它只能看到您编写的内容。
用另一种语言,您可以称其为“新手友好的”,例如C#(或Java),这种情况不会出现,因为您总是被迫明确地指定所有返回和参数类型。这使错误更容易理解,因为现在编译器可以告诉哪个分支是错误的:它与显式声明的返回类型不一致。
但是,如果您考虑一下,您只是将问题移到了上游:编译器如何知道显式声明的类型是正确的?编译器只是假设声明的类型是最终真理,但这仅是一个约定。是的,您很熟悉-但是就像按顺序阅读程序一样随意。
但是,如果您发现此方法更简单,则也可以在F#中完全使用它。F#在C#可以(然后是某些地方)的所有地方都允许(尽管不需要)显式类型规范:
let rec twoTwo (s : string) (n : int) : string =
match n with
|0 -> 0 // Error on this line: this expression was expected to have type string, but here has type int
|_ -> s + (twoTwo s (n-1))
实际上,添加显式类型规范是一种常见的调试技术。当我发现自己的类型不匹配错误不是很明显时,我开始向事情添加类型规范,直到该错误成为焦点。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句