Tengo un ejercicio en Python de la siguiente manera:
un polinomio se da como una tupla de coeficientes de modo que las potencias están determinadas por los índices, por ejemplo: (9,7,5) significa 9 + 7 * x + 5 * x ^ 2
escribir una función para calcular su valor para x dado
Como estoy en la programación funcional últimamente, escribí
def evaluate1(poly, x):
coeff = 0
power = 1
return reduce(lambda accu,pair : accu + pair[coeff] * x**pair[power],
map(lambda x,y:(x,y), poly, range(len(poly))),
0)
que considero ilegible, así que escribí
def evaluate2(poly, x):
power = 0
result = 1
return reduce(lambda accu,coeff : (accu[power]+1, accu[result] + coeff * x**accu[power]),
poly,
(0,0)
)[result]
que es al menos tan ilegible, así que escribí
def evaluate3(poly, x):
return poly[0]+x*evaluate(poly[1:],x) if len(poly)>0 else 0
que podría ser menos eficiente (editar: ¡me equivoqué!) ya que usa muchas multiplicaciones en lugar de exponenciación, en principio, no me importan las mediciones aquí (editar: ¡Qué tonto de mi parte! ¡La medición habría señalado mi error!) y todavía no es tan legible (posiblemente) como la solución iterativa:
def evaluate4(poly, x):
result = 0
for i in range(0,len(poly)):
result += poly[i] * x**i
return result
¿Existe una solución puramente funcional tan legible como la imperativa y cercana a la eficiencia?
Es cierto que un cambio de representación ayudaría, pero esto fue dado por el ejercicio.
También puede ser Haskell o Lisp, no solo Python.
for
bucles, por ejemplo) es un mal objetivo al que apuntar en Python. Volver a vincular variables juiciosamente y no mutar objetos le brinda casi todos los beneficios y hace que el código sea infinitamente más legible. Como los objetos numéricos son inmutables y solo vuelven a unir dos nombres locales, su solución "imperativa" se da cuenta mejor de las virtudes de programación funcional que cualquier código Python "estrictamente puro".lambda
, en comparación con los idiomas con una función de sintaxis anónima más ligera. Parte de eso probablemente contribuye a la apariencia "inmunda".Respuestas:
El método de Horner es probablemente más eficiente desde el punto de vista computacional como señala @delnan, pero yo llamaría a esto bastante legible en Python para la solución de exponenciación:
fuente
sum(coeff * X**power for power, coeff in enumerate(poly))
map
yfilter
. También se puede pensar en él como un bucle for de una forma particular, pero los bucles de esa forma son equivalentes al combinador funcitonal mencionado anteriormente.Muchos lenguajes funcionales tienen implementaciones de mapas que le permiten tener un índice entrelazado a través de un mapa. Combina eso con una suma y tienes lo siguiente en F #:
fuente
map
funciona, debería ser bastante simple escribir uno propio.No entiendo cómo se relaciona su código con el alcance del problema que definió, así que le daré mi versión de lo que hace su código ignorando el alcance del problema (basado en el código imperativo que escribió).
Haskell bastante legible (este enfoque se puede traducir fácilmente a cualquier lenguaje FP que tenga una lista de desestructuración y salga puro y legible):
A veces, el enfoque simple e ingenuo en Haskell es más limpio que el enfoque más conciso para las personas menos acostumbradas a la PF.
Un enfoque más claramente imperativo que todavía es completamente puro es:
La ventaja del segundo enfoque es que estar en la Mónada ST funcionará muy bien.
Aunque para estar seguros, la implementación real más probable de un Haskeller sería el código postal mencionado en otra respuesta anterior.
zipWith
Es un enfoque muy típico y creo que Python puede imitar el enfoque de compresión de combinar funciones y un indexador que se puede mapear.fuente
Si solo tiene una tupla (fija), ¿por qué no hacer esto (en Haskell)?
Si, en cambio, tiene una lista de coeficientes, puede usar:
o con una reducción como la tenías:
fuente
tuple
un conjunto de valores de tamaño fijo, cada uno de tipos potencialmente diferentes, que no se pueden agregar ni quitar. Nunca entendí realmente por qué un lenguaje dinámico con listas, que acepta entradas heterogéneas, las necesitaría.Hay un conjunto general de pasos que puede usar para mejorar la legibilidad de los algoritmos funcionales:
evaluateTerm
una larga expresión lambda. El hecho de que pueda usar una lambda no significa necesariamente que deba hacerlo .enumerate
ozipWith
.fuente