我尝试以多种方式执行以下功能,但总是出错。 那么我该如何执行constructQuery:
type PersonName =
| FirstOnly of string
| LastOnly of string
| FirstLast of string * string
let constructQuery personName =
match personName with
| FirstOnly(firstName) -> printf "May I call you %s?" firstName
| LastOnly(lastName) -> printf "Are you Mr. or Ms. %s?" lastName
| FirstLast(firstName, lastName) -> printf "Are you %s %s?" firstName lastName
-edit -
我试过调用这样的函数:
constructQuery "himekami"
constructQuery ("himekami" : PersonName.FirstOnly)
constructQuery PersonName.FirstOnly("himekami")
并且产生的错误是这样的:
Analyzer.fs(12,17): error FS0001: This expression was expected to have type
PersonName
但这里有类型 串
这是因为我不太了解F#中“type”的方式。
答案 0 :(得分:7)
我想问题是如何构造PersonName
个对象(因为它们是你的函数的输入)。
这很简单 - 只需使用其中一个构造函数FirstOnly
,LastOnly
或FirstLast
:
let firstOnly = FirstOnly "Tom"
let lastOnly = LastOnly "Hengs"
let firstLast = FirstLast ("Tom", "Hengs")
你可以像这样使用它们:
constructQuery firstOnly
constructQuery lastOnly
constructQuery firstLast
您看到PersonName
是一个带有它的3个构造函数的代数数据类型,constructQuery
只匹配它们的唯一参数。在VisualStudio(或MonoDevelop)中,你应该能够得到一个工具提示,其中包含每个部分的类型 - 你应该一直这样做,因为类型是一个很重要的部分理解。
您可以使用管道操作符|>
并一次执行此操作:
FirstOnly "Tom"
|> constructQuery
当然你也可以在没有这个操作员的情况下使用它:
constructQuery (LastOnly "Hengs")
但是你需要parens,因为没有它们你会将函数 LastOnly
(是的,这是一个函数String -> PersonName
)插入函数constructQuery
然后像这样应用字符串:
constructQuery LastOnly "Hengs" = (constructQuery LastOnly) "Hengs" // error: compiler complains about mismatched types
因为LastOnly
实际上是一个函数(遗憾的是C#构造函数不是这样)你也可以做这样的酷事:
// Pipes all the way
"Hengs" |> LastOnly |> constructQuery
// this is another function String -> PersonName
let constructFromLastOnly = LastOnly >> constructQuery
// you can call it like this
constructFromLastOnly "Hengs"
// etc. ... imagine
另一种选择是使用向后管道<|
(不是那么惯用):
constructQuery <| LastOnly "Hengs"
你不需要parens
我会鼓励你(即使编译器并不真的需要它)给出顶级函数的类型(你想从程序的其他部分使用):
let constructQuery (personName : PersonName) : () =
match personName with
// ...
除了拨打personName
之外,您是否发现自己并不真正需要match
?
这是如此常见,以至于有另一种/更短的方式来写这个:
let constructQuery = function
| FirstOnly(firstName) -> printf "May I call you %s?" firstName
| LastOnly(lastName) -> printf "Are you Mr. or Ms. %s?" lastName
| FirstLast(firstName, lastName) -> printf "Are you %s %s?" firstName lastName
或签名:
let constructQuery : PersonName -> () =
function
| FirstOnly(firstName) -> printf "May I call you %s?" firstName
| LastOnly(lastName) -> printf "Are you Mr. or Ms. %s?" lastName
| FirstLast(firstName, lastName) -> printf "Are you %s %s?" firstName lastName
最后 - 我不喜欢你在那里混合printf
的事实。
看一个函数返回单位()
从来都不是纯粹的,你混淆了问题。为什么不这样:
let constructQuery : PersonName -> string =
function
| FirstOnly(firstName) -> sprintf "May I call you %s?" firstName
| LastOnly(lastName) -> sprintf "Are you Mr. or Ms. %s?" lastName
| FirstLast(firstName, lastName) -> sprintf "Are you %s %s?" firstName lastName
并像这样使用它:
FirstOnly "Tom"
|> constructQuery
|> Console.WriteLine
所以你可以重用它,例如在WPF应用程序或控制台不可用的日志记录场景中。