问题描述
我正在尝试编写此模式匹配递归表达式
let rec drop_last l =
match l with
| [] -> []
| [_] -> []
| h::t -> h :: drop_last t ;;
作为 'if statement' 递归表达式。 我已经开始做以下事情:
let rec drop_last2 l =
if l = [] then [] else
if l = [_] then [] else
l = List.hd::List.tl then List.hd::drop_last2 (List.tl l);;
但是,我收到来自编译器的语法错误。有人能告诉我我应该如何将这个 if 语句修改为正确的内容吗?
解决方法
构造 [_]
是一个模式,而不是一个值。因此,您不能像尝试那样使用 =
将其与某个值进行比较。
我相信,要做的就是集中精力考虑列表的长度。模式 []
在长度为 0 时匹配,模式 [_]
在长度为 1 时匹配。您可以在 if
语句中使用这些事实。
正如 Jeffrey 所说,[_]
是一种模式而不是值,您无法与之相比。
并且在 l = List.hd::List.tl
中首先它是不正确的,List.hd
是一个函数,它接受一个列表并返回它的头部,List.tl
也是一个接受一个列表的函数,但是这个返回它的尾部,构造函数 _::_
接受一个值和一个相同类型的值列表。因此,您应该查看文档 (https://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html) 以获取有关如何使用函数和构造函数的更多信息。
从这里开始:
let rec drop_last l =
match l with
| [] -> []
| [_] -> []
| h::t -> h :: drop_last t ;;
对于 if 语句,你可以这样做:
let rec drop_last l =
if List.length l <= 1
then []
else List.hd l :: drop_last (List.tl l) ;;
那是因为模式[]
检查列表是否为空,所以可以用List.length l = 0
替换,[_]
检查列表是否有一个元素,所以可以替换by List.length l = 1
并且因为在这两种情况下你都返回 []
,你可以用 List.length l <= 1
加入它们,List.hd
需要一个列出列表的参数,所以它需要被应用到 l
为您提供头部,然后将尾部附加到递归调用以创建要返回的新列表。