这是一个定义的列表:
type ilist =
E
| L of int * ilist
其中构造函数E代表空列表,构造函数L通过在另一个列表前添加数字来构建列表。
然后可以用一个顺序表示一个元素为1,4,6,7的列表,其中ilist值为:L(1,L(4,L(6,L(7,E)) ))
现在我需要实现一个remove()函数来从列表中删除元素的所有出现。例如,删除2(L(1,L(2,L(3,L(3,L(2,E))))))是L(1,L(3,L(3,E)))
这是我的解决方案:
let rec remove (x:int) (l:list)=
match (x, l) with
| (_, E)->E
| (_, L(x, l1)) -> remove (x) (l1)
| (_, L(y, l1)) -> L(y, remove (x)(l1)) // Warning: This line will never be matched
如您所见,第三种情况永远不会匹配。我如何处理这种情况,以便我可以在列表中维护元素,如果它不是x?
正确的解决方案:
let rec remove (x:int) (l:ilist) =
match l with
| E->E
| L(y, l1) when x==y -> remove x l1
| L(y, l1) -> L(y, remove x l1)
答案 0 :(得分:3)
非常宽松地说,在模式匹配中,你给匹配语句后面的东西一个新名称。 match (x, l)
表示:你接受你的论点,分解它们,分配新的名字。在你的第二个匹配子句中,你基本上说:忽略元组的第一部分。对于列表,请为head元素指定名称x
,其余为名称l1
。现在,这个新名称x
会影响你的论点x
。特别是,这不被解释为“如果列表的第一个元素是x
,那么就......”
这也解释了为什么你的第三个匹配子句永远不会匹配:你是否给头元素命名为x
或y
并不重要 - 它匹配相同类型的列表。
另请注意,所有匹配条款都有_
,您可以更改为match l with
并删除所有_
。你所追求的是像
match l with
| E -> E
| L(head, rest) when head = x -> rest
| L(head, rest) -> L(head, remove x rest)
这里也是一个非常好的article about pattern matching.