Edit: Aunque aparentemente me perdí la diana en la pregunta real, creo que mi respuesta es bastante buena, así que lo estoy guardando :-) (ver abajo).
Supongo que una forma más concisa de expresar la pregunta podría ser: ¿puede un lenguaje puramente funcional calcular algo que es imperativo?
En primer lugar, supongamos que tomó un lenguaje imperativo como C y lo hizo para que no pueda alterar las variables después de definirlas. Por ejemplo:
int i;
for (i = 0; // okay, that's one assignment
i < 10; // just looking, that's all
i++) // BUZZZ! Sorry, can't do that!
Bueno, ahí va su lazo for
. ¿Podemos mantener nuestro loop while
?
while (i < 10)
Claro, pero no es muy útil. i
no se puede cambiar, por lo que se ejecutará para siempre o no se ejecutará en absoluto.
¿Qué tal la recursividad? Sí, usted tiene que mantener la recursividad, y sigue siendo un montón de utilidad:
int sum(int *items, unsigned int count)
{
if (count) {
// count the first item and sum the rest
return *items + sum(items + 1, count - 1);
} else {
// no items
return 0;
}
}
Ahora, con funciones, que no alteran el estado, pero las variables puede, además, variar. Una vez que una variable pasa a nuestra función, está bloqueada. Sin embargo, podemos llamar a la función nuevamente (recursividad), y es como obtener un nuevo conjunto de variables (las antiguas siguen siendo las mismas). Aunque hay varias instancias de items
y count
, sum((int[]){1,2,3}, 3)
siempre evaluará a 6
, por lo que puede reemplazar esa expresión con 6
si lo desea.
¿Todavía podemos hacer lo que queramos? No estoy 100% seguro, pero creo que la respuesta es "sí". Sin dudas, puedes si tienes cierres.
Lo tienes todo. La idea es que una vez que se define una variable, no se puede redefinir. Una expresión referencialmente transparente, dadas las mismas variables, siempre produce el mismo valor de resultado.
Recomiendo buscar en Haskell, un lenguaje puramente funcional. Haskell no tiene un operador de "asignación", estrictamente hablando. Por ejemplo:
my_sum numbers = ??? where
i = 0
total = 0
Aquí, no puede escribir un "bucle for" que incrementa i y el total a medida que avanza. Todo no esta perdido. Sólo tiene que utilizar la recursividad para seguir recibiendo nueva i
s y total
s:
my_sum numbers = f 0 0 where
f i total =
if i < length numbers
then f i' total'
else total
where
i' = i+1
total' = total + (numbers !! i)
(Tenga en cuenta que esta es una manera estúpida para sumar una lista en Haskell, pero demuestra un método de hacer frente a una sola tarea.)
Ahora, considere el código de aspecto altamente imperativo:
main = do
a <- readLn
b <- readLn
print (a + b)
es el azúcar sintáctica realidad para:
La idea es que, en lugar de que main sea una función que consta de una lista de sentencias, main es una acción IO que ejecuta Haskell, y las acciones se definen y encadenan junto con operaciones de vinculación. Además, una acción que no hace nada, que produce un valor arbitrario, se puede definir con la función return
.
Tenga en cuenta que vincular y devolver no son específicos de las acciones. Se pueden usar con cualquier tipo que se llame a sí mismo una Mónada para hacer todo tipo de cosas funky.
Para aclarar, considere readLn
. readLn
es una acción que, si se ejecuta, leerá una línea de entrada estándar y arrojará su valor analizado.Para hacer algo con ese valor, no se puede almacenar en una variable, ya que violaría transparencia referencial:
a = readLn
Si esto se permite, el valor de un dependería del mundo y sería diferente cada vez llamamos readLn
, lo que significa readLn
no sería referencialmente transparente.
En su lugar, se unen la acción readLn a una función que se ocupa de la acción, produciendo una nueva acción, así:
readLn >>= (\x -> print (x + 1))
El resultado de esta expresión es un valor de acción. Si Haskell se baja del sofá y realiza esta acción, leerá un número entero, lo incrementará e imprimirá. Al vincular el resultado de una acción a una función que hace algo con el resultado, obtenemos transparencia referencial mientras jugamos en el mundo del estado.
"eso significa que con un lenguaje funcional puro ... es posible describir solo la lógica secuencial" - ¿no prefieres decir "lógica combinacional"? –
muchas gracias! eso es crucial! – Halst
¿Podría explicar por qué la afirmación "un lenguaje funcional puro solo puede describir la lógica combinacional" es falsa? Gracias. –