Bueno, tener ambos disponibles en lugar de uno solo le da al programador un control más estricto en el alcance. Con let x = e1 in e2
, el enlace solo está presente en el entorno e2
, mientras que con let rec x = e1 in e2
el enlace está presente en los entornos e1
y e2
.
(Edit: Quiero hacer hincapié en que es no un problema de rendimiento, que no hace ninguna diferencia en absoluto.)
Aquí hay dos situaciones en las que tener esta unión no recursivo es útil:
sombreando una definición existente con un refinamiento que usa el enlace anterior. Algo como: let f x = (let x = sanitize x in ...)
, donde sanitize
es una función que asegura que la entrada tenga alguna propiedad deseable (por ejemplo, toma la norma de un vector posiblemente no normalizado, etc.). Esto es muy útil en algunos casos.
metaprogramación, por ejemplo macro escritura. Imagine que quiero definir una macro SQUARE(foo)
que desensanca en let x = foo in x * x
, para cualquier expresión foo
. Necesito este enlace para evitar la duplicación de código en la salida (no quiero que SQUARE(factorial n)
calcule factorial n
dos veces). Esto solo es higiénico si el enlace let
no es recursivo, de lo contrario no podría escribir let x = 2 in SQUARE(x)
y obtener un resultado correcto.
Por lo tanto, afirmo que es muy importante contar con el enlace recursivo y no recursivo disponible. Ahora, el comportamiento predeterminado de del let-binding es una cuestión de convención. Se podría decir que let x = ...
es recursivo, y se debe usar let nonrec x = ...
para obtener la carpeta no recursiva. Escoger uno por defecto u otro es una cuestión de qué estilo de programación desea favorecer y hay buenas razones para elegir. Haskell sufre¹ de la falta de disponibilidad de este modo no recursivo, y OCaml tiene exactamente el mismo defecto en el nivel de tipo: type foo = ...
es recursivo, y no hay una opción no recursiva disponible; consulte this blog post.
¹: cuando Google Code Search estaba disponible, lo usé para buscar en el código de Haskell para el patrón let x' = sanitize x in ...
. Esta es la solución habitual cuando el enlace no recursivo no está disponible, pero es menos seguro porque te arriesgas a escribir x
en lugar de x'
por error más adelante; en algunos casos quieres tener ambos disponibles, por lo que elegir un nombre diferente puede ser voluntario. . Una buena expresión sería usar un nombre de variable más larga para el primer x
, como unsanitized_x
. De todos modos, buscando x'
litterally (sin otro nombre de variable) y x1
dieron muchos resultados. Erlang (y todos los lenguajes que intentan dificultar el sombreado variable: Coffeescript, etc.) tienen problemas aún peores de este tipo.
Dicho esto, la opción de tener enlaces Haskell recursivos por defecto (en lugar de no recursivo) ciertamente tiene sentido, ya que es coherente con la evaluación diferida por defecto, lo que hace que sea muy fácil construir valores recursivos, mientras que los lenguajes por defecto tienen más restricciones sobre las definiciones recursivas que tienen sentido.
¿Por qué votar para cerrar ..? Parece una pregunta razonable. – Sean
Ver http://stackoverflow.com/questions/900585/why-are-functions-in-ocaml-f-not-recursive-by-default –
@Sean: esta es una super-FAQ. – Ashe