La parte intrincada es el bucle. Comencemos con eso. Un bucle generalmente se convierte en estilo funcional al expresar la iteración con una sola función. Una iteración es una transformación de la variable de bucle.
Aquí hay una implementación funcional de un bucle general:
loop : v -> (v -> v) -> (v -> Bool) -> v
loop init iter cond_to_cont =
if cond_to_cont init
then loop (iter init) iter cond
else init
Toma (un valor inicial de la variable de bucle, la función que expresa una única iteración [en la variable de bucle]) (una condición para continuar el bucle).
Su ejemplo usa un bucle en una matriz, que también se rompe. Esta capacidad en su idioma imperativo está integrada en el lenguaje mismo. En la programación funcional, dicha capacidad generalmente se implementa a nivel de biblioteca. Aquí hay una posible implementación
module Array (foldlc) where
foldlc : v -> (v -> e -> v) -> (v -> Bool) -> Array e -> v
foldlc init iter cond_to_cont arr =
loop
(init, 0)
(λ (val, next_pos) -> (iter val (at next_pos arr), next_pos + 1))
(λ (val, next_pos) -> and (cond_to_cont val) (next_pos < size arr))
En eso :
Utilizo un par ((val, next_pos)) que contiene la variable de bucle visible en el exterior y la posición en la matriz, que oculta esta función.
La función de iteración es un poco más compleja que en el bucle general, esta versión permite utilizar el elemento actual de la matriz. [Está en forma de curry .]
Dichas funciones generalmente se denominan "pliegue".
Pongo una "l" en el nombre para indicar que la acumulación de los elementos de la matriz se realiza de forma asociativa a la izquierda; para imitar el hábito de los lenguajes de programación imperativos para iterar una matriz de índice bajo a alto.
Puse una "c" en el nombre para indicar que esta versión de fold toma una condición que controla si y cuando el ciclo se detiene antes.
Por supuesto, es probable que tales funciones de utilidad estén fácilmente disponibles en la biblioteca base incluida con el lenguaje de programación funcional utilizado. Los escribí aquí para demostración.
Ahora que tenemos todas las herramientas que están en el idioma en el caso imperativo, podemos recurrir para implementar la funcionalidad específica de su ejemplo.
La variable en su ciclo es un par ('respuesta', un booleano que codifica si continuar).
iter : (Int, Bool) -> Int -> (Int, Bool)
iter (answer, cont) collection_element =
let new_answer = answer + collection_element
in case new_answer of
10 -> (new_answer, false)
150 -> (new_answer + 100, true)
_ -> (new_answer, true)
Tenga en cuenta que utilicé una nueva "variable" 'new_answer'. Esto se debe a que en la programación funcional no puedo cambiar el valor de una "variable" ya inicializada. No me preocupa el rendimiento, el compilador puede volver a utilizar la memoria de 'respuesta' para 'nueva_respuesta' a través del análisis de por vida, si cree que es más eficiente.
Incorporando esto en nuestra función de bucle desarrollada anteriormente:
doSomeCalc :: Array Int -> Int
doSomeCalc arr = fst (Array.foldlc (0, true) iter snd arr)
"Array" aquí es el nombre del módulo que exporta la función foldlc.
"puño", "segundo" representan funciones que devuelven el primer y segundo componente de su par de parámetros
fst : (x, y) -> x
snd : (x, y) -> y
En este caso, el estilo "sin puntos" aumenta la legibilidad de la implementación de doSomeCalc:
doSomeCalc = Array.foldlc (0, true) iter snd >>> fst
(>>>) es la composición de la función: (>>>) : (a -> b) -> (b -> c) -> (a -> c)
Es lo mismo que arriba, solo el parámetro "arr" se deja fuera de ambos lados de la ecuación de definición.
Una última cosa: verificar el caso (array == null). En lenguajes de programación mejor diseñados, pero incluso en lenguajes mal diseñados con cierta disciplina básica, se utiliza un tipo opcional para expresar la no existencia. Esto no tiene mucho que ver con la programación funcional, de la cual se trata la pregunta en última instancia, por lo tanto, no trato con eso.
break
yreturn answer
se puede reemplazar por unreturn
dentro del bucle. En FP, podría implementar este retorno temprano utilizando continuaciones, consulte, por ejemplo, en.wikipedia.org/wiki/Continuation