所以我在学习如何使用函数式编程的早期阶段,当我尝试将字符串与列表中的字符串进行比较时遇到了这个问题,这样我就可以得到匹配的模式。
这是我的代码:
F#代码
type name = string;;
type number = string;;
type sex = string;;
type year = int;;
type interest = string list;;
type criteria = (sex * year * interest) list;;
type Register = (name * number * criteria) list;;
let reg = [("Lars","28551086",("male",1992,["soccer";"golf"])); ("Hanne","28598653",("female",1989,["cooking";"jewelry"]));
("Viktor","26587297",("male",1973,["clothes";"soccer"])); ("Henrik","22157864",("male",1985,["internet";"facebook"]));
("Lotte","23589462",("female",1997,["bombing";"internet"])); ("Susanne","25896742",("female",1923,["soccer";"cooking"]));
("Marie","22658943",("female",1975,["clothes";"jewelry"])) ];;
let rec findYear n = function
| [] -> failwith("No person with that year is registrered")
| (name,_,(_,n',_)) when n = n' -> name
| (name,_,(_,n',_))::tail when n <> n' -> findYear(tail);;
我想要做的是检索 reg 中与我搜索的名称相同的所有人。 所以F#Interactive调用可以是:
findYear 1992;;
然后它应该给我那一年的人的详细信息。我不知道如何搜索我的 reg
答案 0 :(得分:3)
我想你在这里忘记了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
(应该有错误
试试这个:
let rec findYear n = function
| [] -> failwith("No person with that year is registrered")
| ((name,_,(_,n',_))::_) when n = n' -> name
| ((_,_,(_,n',_))::tail) when n <> n' -> findYear n tail
let rec findYear n = function
| [] -> failwith("No person with that year is registrered")
| ((name,_,(_,n',_))::_) when n = n' -> name
| (_::tail) -> findYear n tail
option
优于异常你处理今年没有找到一个人的情况的方式告诉我们你的功能是&#34;部分&#34; (不会为每个输入返回) - 所以只需使用option
:
let rec findYear n = function
| [] -> None
| ((name,_,(_,n',_))::_) when n = n' -> Some name
| (_::tail) -> findYear n tail
这不会抛出并告诉用户:&#34;嘿,我可能会失败,所以更好地处理这个!&#34;
虽然你的元组很好,但它们并不是真的可读(很难检查你的模式是否正常) - 为什么不使用记录和代数数据类型:
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
模块你在这里做的是一个非常的常见模式,它已经实现了(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
let filterRegistrationWithYear year =
let hasYear (reg : Register) = reg.criteria.year = year
List.filter 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
备注:
我不建议您自己实施这类内容 - 最好使用List
中提供的内容(例如,它更高效,因为我试图向您展示怎么做CPS式)
答案 1 :(得分:1)
如果要使用递归,可以添加其他参数(累加器),以收集结果:
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
或者您可以使用&#39;过滤器&#39;列表库函数中的函数:
let findYear' n lst =
lst |> List.filter (fun (name,_,(_,n',_)) -> n = n')
并以这种方式称呼它:
findYear' 1973 reg