【问题标题】:How to execute this F# function如何执行这个 F# 函数
【发布时间】:2014-08-13 05:38:20
【问题描述】:

我尝试以多种方式执行以下功能,但总是出错。 那么我该如何执行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

-编辑-。

我试过这样调用函数:

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# 中“类型”的工作方式。

【问题讨论】:

  • 请编辑问题以说明您尝试了哪些方法以及遇到了哪些错误。

标签: f#


【解决方案1】:

我想问题是如何构造 PersonName 对象(因为这些是您函数的输入)。

这很简单 - 只需使用构造函数之一 FirstOnlyLastOnlyFirstLast

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")

但在这里你需要括号,因为没有它们你会将 函数 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"

你也不需要括号

备注

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

let constructQuery (personName : PersonName) : () =
   match personName with
   // ...

您是否发现除了调用match 之外,您真的不需要personName? 这很常见,以至于有另一种/更短的方式来写这个:

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 应用程序或控制台不可用的日志记录场景中。

【讨论】:

  • 这很好。感觉像是亲自辅导的。非常感谢。
  • np - 心情不错 ;) - 问问 - 我们需要更多的 F#ers :D
猜你喜欢
  • 2020-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多