2017-07-07 65 views
1

我在OCaml中为一个学校项目实现了我自己的版本。它被定义为这样的:OCaml中的模式类型错误

type 'a my_list = 
    | Item of ('a * 'a my_list) 
    | Empty 
;; 

我的目标是实现从列表模块20层的功能,并且第n是给了我很多的辛勤工作。它是一个递归函数,它也称为hd和长度函数。下面是代码:

let rec length my_list = 
    match my_list with 
    | Empty -> 0 
    | Item (hd, tl) -> (length tl) + 1 
;; 

let hd my_list = function 
    | Empty -> raise (Failure "hd") 
    | Item (hd, tl) -> hd 
;; 

let rec nth my_list n = 
    let len = (length my_list) in 
    match my_list with 
    | lz when lz < 0 -> raise (Invalid_argument "nth") 
    | sup when n > len - 1 -> raise (Failure "nth") 
    | 0 -> (hd my_list) 
    | _ -> (nth my_list (n - 1)) 
;; 

在编译时,我得到这个错误:

$>ocamlc -w Aelz -warn-error A mylist.ml 
File "mylist.ml", line 44, characters 10-11: 
Error: This pattern matches values of type int 
     but a pattern was expected which matches values of type 'a my_list 

参考以下行第n:| 0 -> (hd my_list)

什么想法? 谢谢

编辑1:谢谢大家对你的wiseful答案,这里是最后的代码:

let rec nth my_list n = 
    if n < 0 then raise (Invalid_argument "nth") else 
    if my_list = Empty then raise (Failure "nth") else 
    if n = 0 then hd my_list else nth (tl my_list) (n-1) 
;; 

编辑2:感谢您的建议,这个人是更强类型:

let rec nth my_list n = 
    if n < 0 then raise (Invalid_argument "nth") else 
      match my_list with 
      | Empty -> raise (Failure "nth") 
      | Item (hd, tl) -> if n=0 then hd else 
        nth tl (n-1) 
;; 
+1

你不应该在'len'而不是'my_list'上匹配吗? – Marth

+0

你是对的,谢谢! – bufferking

+2

计算列表的长度不是要走的路:长度函数需要整个列表遍历,并且在每一次迭代中调用它!你是否曾经用一个计数器遍历列表的单个遍历,从0开始,并且当计数器到达N时返回元素到你所在的位置? – ghilesZ

回答

1

您正在过度使用nth函数。我不确定你写什么意图,但是我正在考虑的方法:

  • 如果n是负数,则会引发错误。
  • 如果列表为空,则引发错误。您无法获得空列表的nth元素。
  • 如果该列表不为空,看n是否等于0
    • 如果是的话,返回列表的头。
    • 如果没有,递归。

另外,作为边注,避免在基本类型的模式匹配。取而代之的

match n with 
| x when x<0 -> (* ... *) 
| _ -> (* ... *) 

喜欢使用if

if n<0 then (* ... *) else (* ... *) 

编辑

在另一方面,与非基本类型打交道时,模式匹配,强烈建议。所以,与其

if my_list = Empty then (* ... *) else (* ... *) 

喜欢以下

match my_list with 
| Empty -> (* ... *) 
| Item (hd, tl) -> (* ... *) 

而且(我认为这是什么导致你nth麻烦),你可以结合这两种方法:

if n < 0 then (* ... *) 
else match my_list with 
    | Empty -> (* ... *) 
    | Item (hd, tl) -> (* ... *) 

match my_list with 
    | Empty -> (* ... *) 
    | Item (hd, tl) -> if n < 0 then (* ... *) else (* ... *) 

提示:后者可能是您所需要的nth

当然,类型检查是在这里,以确保你的类型是在你的代码是一致的。

+0

我特意不给你解决方案,因为你正在学习OCaml。但是要知道OCaml是开源的,所以如果你真的被困住了,你可以看看“真正的”List.nth函数的代码。 ;) – RichouHunter

+0

非常感谢,非常有用的建议:) – bufferking

+0

@bufferking作为一个练习,你也可以尝试一个选项,要么返回一些x或无。 – coredump