Ocaml : 将模式匹配表达式转换为 if 表达式 (if.​​.. then... else)

问题描述

我正在尝试编写此模式匹配递归表达式

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 为您提供头部,然后将尾部附加到递归调用以创建要返回的新列表。