gpt4 book ai didi

lambda - F# 查询内部集合

转载 作者:行者123 更新时间:2023-12-02 09:55:48 28 4
gpt4 key购买 nike

在 F# 中,我找不到根据内部集合中项目的属性查询集合的直观方法。例如,考虑地址簿的场景。它包含多个人的记录,每个人可以有多个电子邮件地址或电话号码。类型有:

type Email = {Email : string}
type PhoneNumber = {Number : string}
type Person = {Name : string; EmailAdresses : seq<Email>; PhoneNumbers : seq<PhoneNumber>}

我想编写一个函数来尝试根据电话号码查找人员。由于电话号码是唯一的,我希望该函数返回一个人或不返回任何人,例如函数签名变为

string->seq<Person>->Person option

我想出了

let ``find person by phone number`` number ppl= 
ppl |> Seq.tryFind(fun r -> Seq.exists (fun p -> p.Number = number) r.PhoneNumbers)

Q1:我认为这个查询可读性不太好,可以用任何清洁剂编写吗?

Q2:我还希望能够查询其他内部集合,例如电子邮件地址。我不想定义另一个函数通过电子邮件地址查找人员,而是想探索更通用的方法。作品如下:

let findPerson (propSelector : Person -> seq<'a>)  (pred : seq<'a> -> bool) ppl = 
ppl |> Seq.tryFind (propSelector >> pred)

(为了清楚起见,包括类型。)要调用这个函数,我必须这样做

ppl |> findPerson (fun x -> x.EmailAdresses) (fun p -> p |> Seq.exists (fun n -> n.Email = "john.doe@nowhere.com"))

lambda 再次变得丑陋,尤其是第二个。关于如何改进此代码有什么建议吗?

最佳答案

type Email = string
type PhoneNumber = string
type Name = string
type Person =
{Name:Name; EmailAddresses:seq<Email>; PhoneNumbers:seq<PhoneNumber>}

let findPerson (propSelector : Person -> seq<'a>) (pred : 'a -> bool) =
Seq.tryFind (propSelector >> Seq.exists pred)

let ``find person with john doe email``:(seq<Person> -> Person option) =
findPerson
(fun person -> person.EmailAddresses)
(fun email -> email = "john.doe@nowhere.com")

// .. start with a sequence of people
ppl |> ``find person with john doe email``

(* Alternate *)
ppl |> findPerson
(fun person -> person.EmailAddresses)
(fun email -> email = "john.doe@nowhere.com")

注意:类型可以很简单:

type Email = string

在 findPerson 中,您不需要提及 ppl,因为没有它您将返回一个采用 seq 的函数。比较

let findPerson (propSelector : Person -> seq<'a>)  (pred : 'a -> bool) = 
Seq.tryFind (propSelector >> Seq.exists pred)

let findPerson (propSelector : Person -> seq<'a>)  (pred : 'a -> bool) ppl = 
ppl |>Seq.tryFind (propSelector >> Seq.exists pred)

我已将 Seq.exists 调用移至 findPerson 方法中,以便在传入的 lambda 中不需要它。这允许传入的函数专注于该项目,而不是该项目整个序列。据推测,该方法需要一个序列属性。

最终的调用可以是调用

let ``find person with john doe email``:(seq<Person> -> Person option) = 
findPerson
(fun person -> person.EmailAddresses)
(fun email -> email = "john.doe@nowhere.com")

或者简单地

ppl |> findPerson 
(fun person -> person.EmailAddresses)
(fun email -> email = "john.doe@nowhere.com")

[编辑]

此外,您可以考虑将函数通过管道连接在一起,而不是使用括号。我认为这样读起来更自然一些。

let findPerson (propSelector : Person -> seq<'a>)  (pred : 'a -> bool) = 
propSelector >> Seq.exists pred |> Seq.tryFind

产生这个

type Email = string
type PhoneNumber = string
type Name = string
type Person =
{Name:Name; EmailAddresses:seq<Email>; PhoneNumbers:seq<PhoneNumber>}

let findPerson (propSelector : Person -> seq<'a>) (pred : 'a -> bool) =
propSelector >> Seq.exists pred |> Seq.tryFind

ppl |> findPerson
(fun person -> person.EmailAddresses)
(fun email -> email = "john.doe@nowhere.com")

关于lambda - F# 查询内部集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32028353/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com