假设我有一个由元组列表制作的自制词典
let menu = [("pizza",17);("hotdog",5);("burger", 12);("drink",3);("milkshake",4)]
我想写一个搜索函数,它将我的字典和键值作为参数,然后返回一个选项类型,如果键可以在dict中找到,则返回None
,如果它不能。
我觉得这是一个围绕crypto
,f# recursion以及using and returning option types构建的问题,但是我有一段时间将它们放在一起并获得任何结果甚至远远接近完成这项任务。
我想出了一些我认为可以解决问题的伪代码,但实际的f#实现是另一个故事。在命令式语言中,这似乎是一个微不足道的问题,但试图掌握功能却非常困难。
//create function `search` accepts dictionary and search key
//match searchkey with dictionary key
//if searchkey = dictionary key, return option type w/ value
//if searchkey <> dictionary key, recurse call next dict values
//if end of dictionary, doesn't exist, return none
//Here's a *very* rough sketch of what I think should be happening.
let rec search dict key =
match dict with
//first check for an empty list, if empty return None
| [] -> None
//next check that there is a head and a tail for dict
//also check for match between first element of head and key
//if match, return hd
//still needs to return option type though, but how?
| hd :: tl when fst hd = key -> snd hd
//finally call search on the tail
| _ :: tl -> search tl key
空列表条件和通配符模式我很确定是正确的,但它是实际检查并返回我坚持。我该怎么办呢?
答案 0 :(得分:4)
模式可以嵌套在其他模式中。元组模式(a, b)
可以嵌套在列表头/尾模式head :: tail
中,如下所示:(a, b) :: tail
这意味着第二个模式匹配可能看起来像(k, v) :: _ when k = key
。
您需要从每个分支返回一个选项,因此Some x
或None
。第二个匹配分支缺少Some
包装。
包含这两项更改的代码:
let rec search dict key =
match dict with
| [] -> None
| (k, v) :: _ when k = key -> Some v
| _ :: tl -> search tl key
答案 1 :(得分:1)
他们考虑递归的方法,就是让一个例子正确。并将剩余的列表留给递归函数。并且你必须以某种方式完成“剩余”列表变小。
首先,你要处理一个清单。考虑它的一种方法是一次只检查一个元素。因此,您提取列表的第一个元素,使用它执行某些操作,然后在剩余列表上重复递归函数。所以你可以从:
开始let search key lst =
match lst with
| head :: tail ->
在这种情况下,请考虑您的示例列表。您的head
示例列表的第一次调用将是("pizza",17)
。
您现在需要做的下一步是。将元组解构为key
和value
并检查它们。你用
let (k, v) = head
然后,您需要检查k
是否等于key
。如果它相等,那么你想要返回值。
if k = key
then Some v
else
分支必须处理您的k
不是您搜索的key
的情况。这是递归步骤。您想重复检查剩余的列表项。
else search key tail
请记住此时tail
现在是您的menu
,其中第一个元素已删除。目前您有以下代码。
let rec search key lst =
match lst with
| head :: tail ->
let (k, v) = head
if k = key
then Some v
else search key tail
但是这段代码无法处理无法找到你的项目的情况。想想如果if k = key
永远不真实会发生什么!它将一次删除一个元素,然后在剩余列表中递归,直到您最终得到空列表。
然后空列表意味着,您没有找到密钥。要成功,您现在需要为空列表添加一个案例。在这种情况下,您的密钥不在您的列表中,您必须返回“无”。所以你最终得到:
let rec search key lst =
match lst with
| [] -> None
| head :: tail ->
let (k, v) = head
if k = key
then Some v
else search key tail