这是我的代码:
type noeud = Lettre of (char * bool * arbre_lex)
and arbre_lex = noeud list
exception Deja_defini of string
let rec ajoute mot arbre n =
if existe mot arbre then raise (Deja_defini mot) else
match arbre with
| [] ->
begin
if n+1 = String.length mot then [ Lettre( mot.[n] , true , [] ) ]
else [ Lettre ( mot.[n] , false, ajoute mot arbre (n+1) ) ]
end
| head::tail ->
begin
match head with
| Lettre (mot.[n], b, a) -> (*line 19, source of error*)
begin
if n+1 = String.length mot then [ Lettre ( mot.[n] , true , a ) ]::tail
else [ Lettre ( mot.[n] , b , ajoute mot a (n+1) ) ]::tail
end
| Lettre (_, b, a) -> ajoute mot tail n
end
编译时出现如下错误:
$ocamlc -o main *.ml
File "main.ml", line 19, characters 21-22:
Error: Syntax error: ')' expected
File "main.ml", line 19, characters 17-18:
Error: This '(' might be unmatched
现在我知道我可以改进我的代码,我可以在第一个匹配项中包含第二个匹配项,但是,我特别感兴趣的是找到错误的来源。我尝试了很多东西,但似乎都没有改变错误。
所以请随时发布改进,但我最感兴趣的是如何运行这段确切的代码以帮助避免将来出现错误。
箭头左侧的句法构造不是普通的表达式,而是一种模式。为了方便起见,它看起来很像一个表达式,但它的行为却大不相同。它也是纯粹的编译时构造。
例如,模式
a
,如 Lettre (_, b, a)
将不会评估为 a
的值,或将 a
位置的值与名为 a
的现有绑定的值相匹配。相反,它将创建一个名为 a
的新绑定,它引用 a
位置的值,并隐藏该名称的任何先前绑定。
因此,例如,如果您要匹配的值是
Lettre ('a', true, [])
,a
将在箭头的右侧引用值 []
。而b
将指代true
。
除了作为将值绑定到模式中的名称的方便语法之外,不允许模式中的运行时值允许编译器保证模式匹配的详尽性并在编译时对其进行优化。如果在模式中允许运行时值,您将始终必须提供一个通配符模式来捕捉其余的可能性,因为您将无法在编译时知道哪些可能性可能在运行时匹配。
我希望你现在明白为什么在模式中允许像
mot.[n]
这样的表达式,甚至绑定到 mot.[n]
的值的名称是没有意义的。
但是,有一个独立于模式的构造允许在模式匹配中使用运行时条件,称为“守卫”或“when”子句。使用你的例子:
match head with
| Lettre (ch, b, a) when ch = mot.[n] -> ...
这确实需要一个用通配符代替
ch
的案例,以涵盖守卫不匹配的所有案例。但既然你已经有了,你应该是好人。