List 元组f的搜索列表#

List 元组f的搜索列表#,list,recursion,f#,tuples,List,Recursion,F#,Tuples,假设我有一本用元组列表制作的自制词典 let menu=[(“比萨饼”,17);(“热狗”,5);(“汉堡”,12);(“饮料”,3);(“奶昔”,4)] 我想编写一个搜索函数,将我的字典和键值都作为参数,然后返回一个选项类型,如果在dict中可以找到key,则返回该选项类型的值,如果不能找到,则返回None 我觉得这也是一个围绕着的问题,但是我花了很多时间把它们放在一起,然后得到任何可以实现这项任务的东西 我已经提出了一些我认为可以解决问题的伪代码,但实际的f#实现是另一回事。在命令式语言中,

假设我有一本用元组列表制作的自制词典
let menu=[(“比萨饼”,17);(“热狗”,5);(“汉堡”,12);(“饮料”,3);(“奶昔”,4)]

我想编写一个搜索函数,将我的字典和键值都作为参数,然后返回一个选项类型,如果在dict中可以找到key,则返回该选项类型的值,如果不能找到,则返回
None

我觉得这也是一个围绕着的问题,但是我花了很多时间把它们放在一起,然后得到任何可以实现这项任务的东西

我已经提出了一些我认为可以解决问题的伪代码,但实际的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
//创建函数'search'接受字典和搜索键
//将searchkey与dictionary key匹配
//如果searchkey=dictionary key,则返回选项类型w/值
//如果是searchkey字典键,则递归调用下一个dict值
//如果字典结尾不存在,则返回none
//这是我认为应该发生的事情的一个非常粗略的草图。
让rec搜索dict键=
匹配dict
//首先检查空列表,如果为空,则返回None
|[]->无
//接下来检查dict是否有一个头部和一个尾部
//还要检查头部的第一个元素和键之间是否匹配
//如果匹配,则返回hd
//仍然需要返回选项类型,但是如何返回呢?
|hd::当fst hd=key->snd hd时的tl
//最后调用尾部搜索
|\:tl->搜索tl键

空列表条件和通配符模式我很确定是正确的,但我坚持的是实际的检查和返回。我该如何执行该特定步骤?

模式可以嵌套在其他模式中。元组模式
(a,b)
可以嵌套在列表头/尾模式
head::tail
中,如下所示:
(a,b)::tail

这意味着第二个模式匹配可以如下所示:当k=key时

您需要从每个分支返回一个选项,因此可以是
somex
None
。第二个匹配分支缺少一个
Some
包装器

代码中包含两个更改:

let rec search dict key =
    match dict with       
    | [] -> None
    | (k, v) :: _ when k = key -> Some v
    | _ :: tl -> search tl key

他们认为递归的一种方式,就是把一个例子做对。并将剩余的列表留给递归函数。你必须以某种方式实现“剩余”列表变小

首先,处理一个列表。考虑它的一种方法是一次只检查一个元素。因此,您提取列表的第一个元素,对其执行一些操作,然后对剩余的列表重复递归函数。因此,您可以从以下内容开始:

let search key lst =
    match lst with
    | head :: tail -> 
在本例中,请考虑您的示例列表。第一次调用示例列表时,您的
头将是
(“pizza”,17)

你现在需要做的下一步是。将元组解构为
并检查它们。你可以用

let (k, v) = head
然后您需要检查您的
k
是否等于
key
。如果该值相等,则需要返回该值

if k = key 
then Some v
else
分支必须处理
k
不是您搜索的
键的情况。这是递归步骤。您希望对其余列表项重复检查

else search key tail
请记住,此时
tail
是您的
菜单
,第一个元素已删除。目前您有以下代码

let rec search key lst =
    match lst with
    | head :: tail ->
        let (k, v) = head
        if   k = key
        then Some v
        else search key tail
但此代码无法处理找不到您的项目的情况。想想如果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

我想你需要
将dict与
匹配。另外,要小心你所说的字典。这是.NET中一个众所周知的集合,
dict
已经是一个制作字典的F#函数。字典提供按键的固定时间查找,而您的函数不会这样做,因为它会逐个查找每个元素。实际上,我只是在自己的代码中做了更改,我正在查看它,并意识到我想要与dict匹配。我实际上要更新我的代码。我将确保重命名dict。一旦代码更新,当前问题将返回选项类型!我已经做了一段时间了,我想随着我的进步,我会更新我的代码片段。我甚至可以解决它,我们拭目以待。但是我已经做了很长时间了,我真的很喜欢f。这让人很困惑,但它看起来很优雅。我刚刚把我原来的帖子更新到我现在拥有的内容,我已经接近了!当然不会看起来这么好,但是这个例子会被认为是纯粹的功能吗?我一直回避if-then-else语句,因为我觉得它们不是。我确实喜欢let(k,v)=头,非常有用<代码>如果
不是F#中的语句。它是一个返回值的表达式。这也是为什么
else
分支不是可选的。例如,你也可以写作<代码>设x=如果x%2=0,则设“Foo”或“Bar”
,因为它是一个表达式。非常像
。@Podo是的,甚至本地
绑定和
匹配
都是表达式,而不是F#中的语句。研究面向语句的语言和面向表达式的语言之间的差异是值得的,这样才能充分理解它们之间的差异。与我以前使用的语言相比,这是我最喜欢的F#语言之一。