List 如何从列表中查找类型的值

List 如何从列表中查找类型的值,list,recursion,f#,List,Recursion,F#,因此,我正处于学习如何使用函数式编程的早期阶段,当我试图将字符串与列表中的字符串进行比较,以便获得匹配模式时,我遇到了这个问题 这是我的密码: F代码 然后它会告诉我那一年的详细情况。我不知道如何搜索my reg如果要使用递归,可以添加额外的参数累加器来收集结果: let rec findYear n acc = function | [] -> acc | ((name,_,(_,n',_)) as h)::tail when n = n' -> findYear

因此,我正处于学习如何使用函数式编程的早期阶段,当我试图将字符串与列表中的字符串进行比较,以便获得匹配模式时,我遇到了这个问题

这是我的密码:

F代码


然后它会告诉我那一年的详细情况。我不知道如何搜索my reg

如果要使用递归,可以添加额外的参数累加器来收集结果:

let rec findYear n acc = function
    | [] -> acc
    | ((name,_,(_,n',_)) as h)::tail  when n = n' -> findYear n (h::acc) tail 
    | h::tail -> findYear n acc tail
这样说吧:

findYear 1973 [] reg
findYear' 1973 reg
也可以使用列表库函数中的“过滤器”函数:

let findYear' n lst =
    lst |> List.filter (fun (name,_,(_,n',_)) -> n = n')
这样说吧:

findYear 1973 [] reg
findYear' 1973 reg

如果要使用递归,可以添加额外的参数累加器来收集结果:

let rec findYear n acc = function
    | [] -> acc
    | ((name,_,(_,n',_)) as h)::tail  when n = n' -> findYear n (h::acc) tail 
    | h::tail -> findYear n acc tail
这样说吧:

findYear 1973 [] reg
findYear' 1973 reg
也可以使用列表库函数中的“过滤器”函数:

let findYear' n lst =
    lst |> List.filter (fun (name,_,(_,n',_)) -> n = n')
这样说吧:

findYear 1973 [] reg
findYear' 1973 reg

我想你只是忘记了n和列表的结尾:

let rec findYear n = function
    | [] -> failwith("No person with that year is registrered")
    | (name,_,(_,n',_))  when n = n' -> name // forgot tail
    | (name,_,(_,n',_))::tail  when n <> n' -> findYear(tail) // forgot n here
选择胜于例外 你处理今年没有找到一个人的情况的方式告诉我们,你的函数是部分的,并不是每个输入都返回-所以只需使用选项再次将其设置为总计:

这不会抛出并告诉用户:嘿,我可能会失败,所以最好处理这个

使用记录/ADT 虽然元组很好,但它们不是真正可读的。很难检查您的模式是否正常。例如,为什么不使用记录和代数数据类型:

type Name = string
type Number = string
type Gender = Male | Female // add more if you need
type Year = int
type Interests = string list
type Criteria = { gender : Gender; year : Year; interests : Interests }
type Register = { name : Name; number : Number; criteria : Criteria }

let reg = 
  [ { name = "Lars"
    ; number = "28551086"
    ; criteria = { gender = Male; year = 1992; interests = ["soccer";"golf"] }
    }
    // ...
]
并使用以下命令:

let rec findYear n = 
    function
    | [] -> None
    | (reg::_) when reg.criteria.year = n' 
       -> Some reg
    | (_::regs) 
       -> findYear n regs
使用列表模块 您在这里所做的是一个非常常见的模式,它已经实现了List.tryFind——那么为什么不使用它呢

let findYear n = 
    let hasYear (reg : Register) = reg.criteria.year = n
    List.tryFind hasYear
当然,如果您还不了解部分应用程序,可以添加缺少的参数:

let findYear n regs = 
    let hasYear (reg : Register) = reg.criteria.year = n
    List.tryFind hasYear regs
最后,让我们给它起个更好的名字 这当然只是我不喜欢findYear如果你真的找到了注册

// rest is the same
type Registration = { name : Name; number : Number; criteria : Criteria }

let firstRegistrationWithYear year = 
    let hasYear (reg : Register) = reg.criteria.year = year
    List.tryFind hasYear
查找一年内的所有注册 或者,如果您想要使用延续传递样式的尾部递归实现,则另一个答案具有累加器aproach:

let filterYear n regs = 
    let rec filter regs cont =
       match regs with
       | [] -> cont []
       | (reg::regs) when reg.criteria.year = n' 
          -> filter regs (fun res -> reg::res |> cont)
       | (_::regs) 
          -> filter regs cont
    filter regs id 
备注:
我不建议您自己实现这类功能-最好使用列表中提供的功能,例如,它的性能更高,因为我试图向您展示如何使用CPS样式,我想您只是忘记了列表的n和尾部:

let rec findYear n = function
    | [] -> failwith("No person with that year is registrered")
    | (name,_,(_,n',_))  when n = n' -> name // forgot tail
    | (name,_,(_,n',_))::tail  when n <> n' -> findYear(tail) // forgot n here
选择胜于例外 你处理今年没有找到一个人的情况的方式告诉我们,你的函数是部分的,并不是每个输入都返回-所以只需使用选项再次将其设置为总计:

这不会抛出并告诉用户:嘿,我可能会失败,所以最好处理这个

使用记录/ADT 虽然元组很好,但它们不是真正可读的。很难检查您的模式是否正常。例如,为什么不使用记录和代数数据类型:

type Name = string
type Number = string
type Gender = Male | Female // add more if you need
type Year = int
type Interests = string list
type Criteria = { gender : Gender; year : Year; interests : Interests }
type Register = { name : Name; number : Number; criteria : Criteria }

let reg = 
  [ { name = "Lars"
    ; number = "28551086"
    ; criteria = { gender = Male; year = 1992; interests = ["soccer";"golf"] }
    }
    // ...
]
并使用以下命令:

let rec findYear n = 
    function
    | [] -> None
    | (reg::_) when reg.criteria.year = n' 
       -> Some reg
    | (_::regs) 
       -> findYear n regs
使用列表模块 您在这里所做的是一个非常常见的模式,它已经实现了List.tryFind——那么为什么不使用它呢

let findYear n = 
    let hasYear (reg : Register) = reg.criteria.year = n
    List.tryFind hasYear
当然,如果您还不了解部分应用程序,可以添加缺少的参数:

let findYear n regs = 
    let hasYear (reg : Register) = reg.criteria.year = n
    List.tryFind hasYear regs
最后,让我们给它起个更好的名字 这当然只是我不喜欢findYear如果你真的找到了注册

// rest is the same
type Registration = { name : Name; number : Number; criteria : Criteria }

let firstRegistrationWithYear year = 
    let hasYear (reg : Register) = reg.criteria.year = year
    List.tryFind hasYear
查找一年内的所有注册 或者,如果您想要使用延续传递样式的尾部递归实现,则另一个答案具有累加器aproach:

let filterYear n regs = 
    let rec filter regs cont =
       match regs with
       | [] -> cont []
       | (reg::regs) when reg.criteria.year = n' 
          -> filter regs (fun res -> reg::res |> cont)
       | (_::regs) 
          -> filter regs cont
    filter regs id 
备注:
我不建议你自己实现这种东西——最好使用列表中提供的东西,例如,它的性能更高,因为我试图向你展示如何使用CPS风格

这很好,我会接受is作为答案。谢谢你的解释。我不知道在records/ADT方法下,Some名字在做什么-你能解释一下吗?不管怎样,我发现了:非常感谢你的帮助!我刚刚发现,如果它与年份相等,它只能在登记册中找到一个人。它应该给我所有的匹配模式^^^是的-你的问题也一样,所以我认为这没问题-但解决办法很简单:将List.tryFind hasYear更改为List.filter hasYear,在最后一部分;。。。当然,您可能想再次更改它的名称;这是好的,我会接受的答案是。谢谢你的解释。我不知道在records/ADT方法下,Some名字在做什么-你能解释一下吗?不管怎样,我发现了:非常感谢你的帮助!我刚刚发现,如果它与年份相等,它只能在登记册中找到一个人。它应该给我所有的匹配模式^^^是的-你的问题也一样,所以我认为这没问题-但解决办法很简单:将List.tryFind hasYear更改为List.filter hasYear,在最后一部分;。。。当然,您可能想再次更改它的名称;