J'ai un exercice en Python comme suit:
un polynôme est donné comme un tuple de coefficients tels que les puissances sont déterminées par les indices, par exemple: (9,7,5) signifie 9 + 7 * x + 5 * x ^ 2
écrire une fonction pour calculer sa valeur pour x donné
Depuis que je suis dans la programmation fonctionnelle ces derniers temps, j'ai écrit
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 je juge illisible, alors j'ai écrit
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]
ce qui est au moins aussi illisible, alors j'ai écrit
def evaluate3(poly, x):
return poly[0]+x*evaluate(poly[1:],x) if len(poly)>0 else 0
ce qui pourrait être moins efficace (éditer: j'avais tort!) car il utilise de nombreuses multiplications au lieu d'exponentiation, en principe, je ne me soucie pas des mesures ici (éditer: comme c'est idiot de ma part! toujours pas aussi lisible (sans doute) que la solution itérative:
def evaluate4(poly, x):
result = 0
for i in range(0,len(poly)):
result += poly[i] * x**i
return result
Existe-t-il une solution purement fonctionnelle aussi lisible que l'impératif et proche de son efficacité?
Certes, un changement de représentation aiderait, mais cela a été donné par l'exercice.
Peut être Haskell ou Lisp, pas seulement Python.
for
boucles, par exemple) est un mauvais objectif à viser en Python. Re-lier judicieusement les variables et ne pas muter les objets vous donne presque tous les avantages et rend le code infiniment plus lisible. Étant donné que les objets numériques sont immuables et ne relient que deux noms locaux, votre solution "impérative" réalise mieux les vertus de programmation fonctionnelle que tout code Python "strictement pur".lambda
, par rapport aux langages avec une fonction de syntaxe anonyme plus légère. Une partie de cela contribue probablement à l'apparence «impure».Réponses:
La méthode de Horner est probablement plus efficace en termes de calcul comme le souligne @delnan, mais j'appellerais cela assez lisible en Python pour la solution d'exponentiation:
la source
sum(coeff * X**power for power, coeff in enumerate(poly))
map
etfilter
. On peut également le considérer comme une boucle for d'une forme particulière, mais les boucles de cette forme sont équivalentes au combinateur fonctionnel susmentionné.De nombreux langages fonctionnels ont des implémentations mapi qui vous permettent d'avoir un index tissé à travers une carte. Combinez cela avec une somme et vous avez ce qui suit en F #:
la source
map
fonctionne, il devrait être assez simple d'écrire l'un des vôtres.Je ne comprends pas comment votre code est lié à la portée du problème que vous avez définie, je vais donc donner ma version de ce que fait votre code en ignorant la portée du problème (en fonction du code impératif que vous avez écrit).
Haskell assez lisible (cette approche peut être facilement traduite dans n'importe quel langage FP qui a une déstructuration de liste et qui sort pur et lisible):
Parfois, l'approche simple et naïve de haskell comme celle-ci est plus propre que l'approche plus concise des personnes moins habituées à la PF.
Une approche plus clairement impérative qui est encore complètement pure est la suivante:
bonus à la deuxième approche est d'être dans la monade ST, il fonctionnera très bien.
Bien que pour être certain, l'implémentation réelle la plus probable d'un Haskeller serait le zipwith mentionné dans une autre réponse ci-dessus.
zipWith
est une approche très typique et je crois que Python peut imiter l'approche zippée de la combinaison de fonctions et d'un indexeur qui peut être mappé.la source
Si vous avez juste un tuple (fixe), pourquoi ne pas le faire (en Haskell):
Si à la place vous avez une liste de coefficients, vous pouvez utiliser:
ou avec une réduction telle que vous l'aviez:
la source
tuple
un ensemble de valeurs de taille fixe, chacun de types potentiellement différents, qui ne peuvent pas être ajoutés ou supprimés. Je n'ai jamais vraiment compris pourquoi un langage dynamique avec des listes, qui acceptent des entrées hétérogènes, en aurait besoin.Il existe un ensemble général d'étapes que vous pouvez utiliser pour améliorer la lisibilité des algorithmes fonctionnels:
evaluateTerm
une longue expression lambda. Tout simplement parce que vous pouvez utiliser un lambda ne signifie pas nécessairement que vous devriez .enumerate
ouzipWith
.la source