2012-01-30 10 views
5

Aquí hay un fragmento de código de mi libro, y no estoy seguro de cómo funciona la coincidencia aparentemente porque parece que el primer caso coincide con todo. Aquí están las advertencias que Ocaml me lanza:¿Por qué el patrón OCaml `zero -> zero` parece coincidir con todo?

# let zero = 0;; 
# let one = 1;; 
# let rec fib i = 
match i with 
zero -> zero 
| one -> one 
| j -> fib (j - 2) + fib (j - 1);; 
Characters 57-60: 


Warning: this match case is unused. 
Characters 74-75: 
Warning: this match case is unused. 
| one -> one 
^^^ 
| j -> fib (j - 2) + fib (j - 1);; 
^ 
val fib : int -> int = <fun> 
# fib 1;; 
- : int = 1 
# fib 2002;; 
- : int = 2002 

Respuesta

9

Esta es una fuente bastante común de confusión. En esencia, desea pensar en los patrones como construidos a partir de constantes (como 0 y 1) e identificadores que están enlazados por el patrón.

Cuando aparece un identificador en un patrón, coincide con cualquier cosa y vincula el valor coincidente con el identificador. Un identificador en un patrón no se refiere a cualquier valor previo asociado con el identificador. Entonces, de hecho, su patrón siempre coincidirá con el primer caso y vinculará zero al valor de i.

Puede imaginarse que le gustaría dar nombres a valores constantes, luego use los nombres en lugar de las constantes en un patrón. Sin embargo OCaml (como otros lenguajes FP) no funciona de esa manera. Una ventaja (me parece) es que mantiene las cosas simples.

+1

Puede utilizar las constantes si hacer algo como 'x donde x == cero' (sin embargo, se me escapa la sintaxis precisa) – hugomg

+2

Puede usar' when' para agregar una prueba adicional a una coincidencia, pero no cambia el significado del patrón. Solo aplica una prueba adicional. Si su patrón es solo un identificador, esta es solo otra forma de escribir una declaración 'if'. (No hay nada de malo con las declaraciones' if', eso es lo que probablemente usaría para probar contra las constantes con nombre.) –

+0

Gracias Jeffrey, encontré esta bonita perspicaz –

0

pensé que me gustaría añadir que si reescribiste el código de la siguiente manera, que funcionaría bien:

# let zero = 0;; 
# let one = 1;; 
# let rec fib i = 
match i with 
    0 -> zero 
| 1 -> one 
| j -> fib (j - 2) + fib (j - 1);; 

El problema fundamental (como se explica bastante bien en la otra respuesta) es que puede crear nuevas variables locales con el mismo nombre que las variables globales y que usar cualquier nombre de variable en el lado izquierdo de la coincidencia solo crea una nueva variable local de ese nombre y lo llena con lo que sea que se esté emparejando. Al igual que j es una nueva variable local que contiene lo que sea que coincida, también lo es zero. Y el hecho de que fue declarado previamente en un ámbito más amplio es ignorado por Ocaml (que es por lo que felizmente puede escribir cosas como

let x = 1;; 
let x = 2 in let x = 3 in x;; 

lo que da un resultado de 3.

+0

Este es un buen punto; la aparición de 'cero' en el patrón crea un ámbito anidado donde' cero' está vinculado a un nuevo valor basado en la coincidencia. La mayoría de los lenguajes de programación admiten ámbitos anidados, no solo OCaml. Las alternativas son generalmente peores; es probable que no desee limitar las opciones de nombres locales dependiendo de los nombres utilizados en otras partes del código. –

Cuestiones relacionadas