如何执行这个F#函数

him*_*ami 0 f#

我尝试以多种方式执行以下函数,但总是出错.那我该如何执行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
Run Code Online (Sandbox Code Playgroud)

-编辑-.

我试过调用这个函数:

constructQuery "himekami"
constructQuery ("himekami" : PersonName.FirstOnly)
constructQuery PersonName.FirstOnly("himekami")
Run Code Online (Sandbox Code Playgroud)

和产生的错误是这样的:

Analyzer.fs(12,17): error FS0001: This expression was expected to have type
PersonName    
Run Code Online (Sandbox Code Playgroud)

但这里有字符串

这是因为我不太了解F#中"类型"的工作方式.

Car*_*ten 7

我想问题是如何构造PersonName对象(因为那些是你的函数的输入).

这很简单 - 只需使用其中一个构造函数FirstOnly,LastOnly或者FirstLast:

let firstOnly = FirstOnly "Tom"
let lastOnly  = LastOnly "Hengs"
let firstLast = FirstLast ("Tom", "Hengs")
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它们:

constructQuery firstOnly
constructQuery lastOnly
constructQuery firstLast
Run Code Online (Sandbox Code Playgroud)

背景

你看到的PersonName是一个带有3个构造函数的代数数据类型,constructQuery匹配它们只是它们的参数.在VisualStudio(或MonoDevelop)中,你应该能够得到一个工具提示,其中包含每个部分的类型 - 你应该一直这样做,因为类型是一个重要的部分理解.

其他方法称此功能

你可以使用管道操作员|>并一次完成:

FirstOnly "Tom"
|> constructQuery
Run Code Online (Sandbox Code Playgroud)

当然你也可以在没有这个操作符的情况下使用它:

constructQuery (LastOnly "Hengs")
Run Code Online (Sandbox Code Playgroud)

但是在这里你需要parens因为没有它们你会把函数 LastOnly(是的,这是一个函数String -> PersonName)插入函数constructQuery然后应用这样的字符串:

constructQuery LastOnly "Hengs" = (constructQuery LastOnly) "Hengs" // error: compiler complains about mismatched types
Run Code Online (Sandbox Code Playgroud)

因为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
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用向后管道<|(不是那么惯用):

constructQuery <| LastOnly "Hengs"
Run Code Online (Sandbox Code Playgroud)

你不需要那些parens的地方

备注

我鼓励你(即使编译器并不真的需要它)给出顶级函数的类型(你想从程序的其他部分使用):

let constructQuery (personName : PersonName) : () =
   match personName with
   // ...
Run Code Online (Sandbox Code Playgroud)

你有没有看到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
Run Code Online (Sandbox Code Playgroud)

或签名:

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
Run Code Online (Sandbox Code Playgroud)

最后 - 我不喜欢你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
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

FirstOnly "Tom"
|> constructQuery
|> Console.WriteLine
Run Code Online (Sandbox Code Playgroud)

所以你可以重用它,例如在WPF应用程序或控制台不可用的日志记录场景中.

  • np - 心情很好;) - 请问 - 我们需要更多F#ers在那里:D (4认同)