2011-03-06 3 views
5

Dans Haskell, deux fonctions permettent d'effectuer une opération sur une liste d'éléments afin de la réduire à une seule valeur. (Il y en a plus de deux, bien sûr, mais ce sont les deux qui m'intéressent.) Ils sont foldl1 et foldr1. Si l'opération à effectuer est commutative (comme l'ajout), peu importe lequel vous utilisez. Le résultat sera le même. Cependant, si l'opération est et non commutative (par exemple, soustraction), alors les deux produisent des résultats très différents. Par exemple:Quelle est la manière la plus efficace d'implémenter foldl1 de Haskell dans J?

foldr1 (-) [1..9] 
foldl1 (-) [1..9] 

La réponse à la première est 5 et à la seconde, -43. L'équivalent de J foldr1 est l'adverbe insert, /, par exemple,

-/ 1+i.9 

qui est l'équivalent de foldr1 (-) [1..9]. Je veux créer un adverbe dans J qui fonctionne comme l'adverbe d'insertion, mais se plie à gauche au lieu de droit. Le mieux que je pouvais trouver est la suivante:

foldl =: 1 : 'u~/@|.' 

Ainsi, on pourrait dire:

- foldl 1+i.9 

et obtenir -43 comme la réponse, qui est ce qu'on attend d'un pli gauche.

Y a-t-il une meilleure façon de le faire dans J? Pour une raison quelconque, inverser l'argument y ne me semble pas efficace. Peut-être y a-t-il un moyen de le faire sans avoir à recourir à cela.

+1

Je ne sais pas s'il y a quelque chose en plus de retourner le tableau, aussi pratique que cela puisse paraître. On pourrait penser (ou espérer) Haskell ne fait pas cela et fonctionne seulement la fonction de la fin ... – MPelletier

+0

Je voulais dire "peu importe comment IMpractical." – MPelletier

Répondre

2

Je ne pense pas qu'il y ait une meilleure façon de plier à gauche que vous décrivez:

(v~)/(|. list) 

Il est une façon très naturelle, une mise en œuvre presque « littérale » de la définition. Le coût de l'inversion de la liste est très faible (imo).

L'autre façon évidente de mettre en œuvre le pli gauche est de mettre

new_list = (first v second) v rest 

par exemple:

foldl_once =: 1 :'(u/0 1 { y), (2}. y)' 
foldl =: 1 :'(u foldl_once)^:(<:#y) y' 

donc:

- foldl >:i.9 
_43 

mais votre chemin effectue beaucoup mieux que ceci à la fois dans l'espace et le temps.

+0

Je vous donne le prix, même si la réponse d'Ephémient était très intéressante, car je pense qu'il est clair que ma solution est probablement la meilleure, bien que je ne puisse pas le prouver. –

1
($:@}:-{:)^:(1<#) 1+i.9 
_43 

Aucune idée si c'est plus (ou moins) efficace.

+0

Difficile à dire. Avec des nombres inférieurs à 4500, votre solution et la mienne sont instantanées. Après cela, le vôtre provoque une erreur de pile et le mien fonctionne très bien. Donc, dans ce sens, le mien est plus efficace, mais avec les ressources, il est difficile de dire lequel est le plus rapide. –

+0

Oh, et j'ai pensé que j'ajouterais que le vôtre est à la fois intelligent et éducatif. –

Questions connexes