【问题标题】:OCaml list syntax errorOCaml 列表语法错误
【发布时间】:2014-03-15 10:44:41
【问题描述】:

我正在编写一个函数来从列表中删除具有相同值的邻居。我不明白这里的语法错误是什么。这就是我所拥有的:

let rec rem_dup_neighb l = 
let rec rem_dup_neighb_aux l lastseen retl = 
match l with 
 []->retl
|[()]->[()]
| (y::rest) -> if(y==lastseen) then rem_dup_neighb_aux l lastseen retl else rem_dup_neighb_aux l y (y::retl)
in rem_dup_neighb_aux l 9000 [];;

函数的最后一行出现以下错误:

Error: This expression has type int but an expression was expected of type
     unit

例如,如果你将 [1;2;2;3;5] 传递给函数,它应该返回 [1;2;3;5]

感谢任何帮助。谢谢

更新: 函数似乎是无限循环:

let rec rem_dup_neighb l = 
let rec rem_dup_neighb_aux l lastseen retl = 
match l with []->retl
| (y::rest) -> if(y==lastseen) then rem_dup_neighb_aux l lastseen retl else rem_dup_neighb_aux l y (y::retl)
in
    match l with
    (lastseen::rest) ->  rem_dup_neighb_aux l lastseen []

更新 2: 没有减少每次迭代的问题。不过,函数现在似乎返回 [5;3;2] 而不是 [1;2;3;5]。

let rec rem_dup_neighb l = 
let rec rem_dup_neighb_aux l lastseen retl = 
match l with []->retl
| (y::rest) -> if(y==lastseen) then rem_dup_neighb_aux rest lastseen retl else rem_dup_neighb_aux rest y (y::retl)
in
    match l with
    []->[]
    |(lastseen::rest) ->  rem_dup_neighb_aux l lastseen []

更新 3:

let rec rem_dup_neighb l = 
let rec rem_dup_neighb_aux l lastseen retl = 
match l with []->retl
| (y::rest) -> if(y==lastseen) then rem_dup_neighb_aux rest lastseen retl else rem_dup_neighb_aux rest y (y::retl)
in
    match l with
    []->[]
    |(lastseen::rest) ->  rem_dup_neighb_aux l lastseen [lastseen]

【问题讨论】:

  • 您更新的函数每次都将相同的列表传递给rem_dup_neighb_aux 的递归调用。您希望每次递归调用都沿列表进行,因此在此处传递 rest
  • 您还缺少底部匹配中的空列表案例。
  • 好的,谢谢。修复了无限循环。嗯,函数返回 [5;3;2] 而不是 [1;2;3;5]。我明白为什么第一个元素被删除了。还需要以某种方式反转输出。
  • List.rev 应该足够了。 (累加一个列表然后在最后反转它是函数式编程中相当常见的模式。)
  • 不允许使用库函数:/

标签: list recursion ocaml


【解决方案1】:

匹配子句[()] -> [()] 接受并产生一个unit list,这在此处没有任何意义。你可能应该写 [_] -> retl, _ 是“匹配任何东西”的匹配语法。

【讨论】:

  • 好的,箭头右侧retl后面的“,_”是什么意思?
  • 所以我只是删除了 [()]->[()] 行并将 []->retl 更改为 [_]->retl。但是,该函数的一个测试用例将 [()] 传递给该函数,因此我收到错误:错误:此表达式具有单元类型,但预期表达式为 int 类型。错误指向测试文件跨度>
  • gsg 是说你的代码中应该有[_] -> retl。然后他继续指出(在逗号之后)_ 是一个匹配任何值的模式。他的标点符号有点混乱。
  • 我明白了。感谢您清除它。如果可能的话,您能否解决我在之前评论中遇到的新问题?
  • 此函数将列表元素与 9000 进行比较,这限制了它只能接受 ints 的列表。
【解决方案2】:

如果其中一个测试用例有 [()] 作为输入,那么您不能使用 9000 作为列表开头的假值。您需要具有与列表中任何内容相同类型的假值。一个想法是使用列表的实际第一个值。

作为旁注,您似乎应该在比赛中取出您的第二个案例。在第二种情况下,我的意思是(在修复代码之后)匹配长度为 1 的列表的模式;即,模式[_]。使用您的方法(使用“最后一次看到”值)只有两种情况,即空列表和非空列表。您的特殊问题出现在列表的开头(正如您现在所遇到的),而不是结尾。

更新

您可以在任何您喜欢的地方进行模式匹配(match 表达式)。所以,你可以在in之后有一个:

let rem_dup_neighbors aList =
    let rec aux l lastseen retl =
        ...
    in
    match aList with
    | pattern1 -> blah blah blah
    | pattern2 -> aux blah blah

更新 2

当递归调用自己时,你必须通过一个较小的问题。你的辅助函数只是不断地用同一个列表调用自己。

【讨论】:

  • 第二种情况,你的意思是 if 语句的 else 部分?另外,你知道如何在不使用库函数的情况下访问列表的第一个元素吗?
  • 查看重写的文本。使用模式匹配访问列表元素。
  • 嗯,我想我需要它作为基本情况,否则函数会无限调用自己。
  • 您的基本情况是 empty 列表。
  • 我认为 [_ ]->retl 就是这样。我将 []->retl 替换为 [_]->retl。你是说离开 []->retl 并删除 [_]->retl?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-09
  • 1970-01-01
相关资源
最近更新 更多