¿Por qué ocaml necesita tanto "let"como" let rec"? [duplicar]


Posible Duplicado:
¿Por qué las funciones en Ocaml/F# no son recursivas por defecto?

OCaml usa let para definir una nueva función, o let rec para definir una función que es recursiva. ¿Por qué necesita ambos-no podríamos simplemente usar let para todo?

Por ejemplo, para definir una función sucesora no recursiva y un factorial recursivo en OCaml (en realidad, en el intérprete OCaml) podría escribir

let succ n = n + 1;;

let rec fact n =
    if n = 0 then 1 else n * fact (n-1);;

Considerando que en Haskell (GHCI) Puedo escribir

let succ n = n + 1

let fact n =
    if n == 0 then 1 else n * fact (n-1)

¿Por qué la OCaml distingue entre let y let rec? Es un problema de rendimiento, o algo más sutil?

Author: Community, 2012-02-17

1 answers

Bueno, tener ambos disponibles en lugar de solo uno le da al programador un control más estricto sobre el alcance. Con let x = e1 in e2, el enlace solo está presente en el entorno de e2, mientras que con let rec x = e1 in e2 el enlace está presente en los entornos de e1 y e2.

(Edit: Quiero enfatizar que es no un problema de rendimiento, que no hace ninguna diferencia en absoluto.)

Aquí hay dos situaciones donde tener esta unión no recursiva es útil:

  • Sombra una definición existente con un refinamiento que utiliza la antigua unión. Algo así como: let f x = (let x = sanitize x in ...), donde sanitize es una función que asegura que la entrada tiene 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 escritura macro. Imagine que quiero definir una macro SQUARE(foo) que desugars 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 SQUARE(factorial n) para calcular 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.

Así que reclamo que es muy importante tener disponible tanto la unión recursiva como la no recursiva. Ahora, el comportamiento por defecto de la 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 el aglutinante no recursivo. Elegir un valor predeterminado o el otro es una cuestión de qué estilo de programación desea favorecer y hay buenas razones para hacer cualquier elección. Haskell sufre 1 de la falta de disponibilidad de este modo no recursivo, y OCaml tiene exactamente el mismo defecto a nivel de tipo : type foo = ... es recursivo, y no hay ninguna opción no recursiva disponible see ver esta entrada de blog.

1: cuando la búsqueda de Código de Google estaba disponible, la usé para buscar en código Haskell 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 corre el riesgo de escribir x en lugar de x' por error más adelante -- en algunos casos desea tener ambos disponibles, por lo que elegir un nombre diferente puede ser voluntario. Un buen modismo sería usar un nombre de variable más largo para el primer x, como unsanitized_x. De todos modos, simplemente buscando x' litterally (ningún otro nombre de variable) y x1 dio muchos resultados. Erlang (y todos los lenguajes que intentan dificultar el sombreado variable: Coffeescript, etc.) tiene problemas aún peores de este tipo.

Dicho esto, la elección de tener enlaces Haskell recursivos por defecto (en lugar de no recursivos) ciertamente tiene sentido, ya que es consistente con la evaluación perezosa por defecto, lo que hace que sea realmente fácil construir valores recursivos while mientras que los lenguajes estrictos por defecto tienen más restricciones sobre qué definiciones recursivas tienen sentido.

 29
Author: gasche,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-17 12:30:31