2011-03-06 10 views
5

En Haskell hay dos funciones que permiten realizar una operación en una lista de elementos para reducirla a un único valor. (Hay más de dos, por supuesto, pero estos son los dos que me interesan). Son foldl1 y foldr1. Si la operación que se realizará es commutative (como adición), no importa cuál de estos utilice. El resultado será el mismo. Sin embargo, si la operación es no conmutativa (por ejemplo, resta), los dos producen resultados muy diferentes. Por ejemplo:¿Cuál es la forma más eficiente de implementar Haskell's foldl1 en J?

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

La respuesta a la primera es 5 y a la segunda, -43. El J equivalente de foldr1 es el adverbio inserto, /, por ejemplo,

-/ 1+i.9 

que es el equivalente de foldr1 (-) [1..9]. Quiero crear un adverbio en J que funcione como el adverbio de inserción, pero dobla a la izquierda en lugar de a la derecha. Lo mejor que podía llegar a decir lo siguiente:

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

Por lo tanto, se podría decir:

- foldl 1+i.9 

y obtener -43 como la respuesta, que es lo que se espera de un pliegue izquierda.

¿Hay alguna forma mejor de hacerlo en J? Por alguna razón, revertir el argumento y no me parece eficiente. Quizás hay una manera de hacer esto sin tener que recurrir a eso.

+1

No sé si existe tal cosa además de voltear la matriz, sin importar lo práctico que parezca. Uno pensaría (o esperaría) que Haskell no hace eso y solo trabaja la función desde el final ... – MPelletier

+0

Quise decir "no importa cuán IMpractical". – MPelletier

Respuesta

2

No creo que hay una mejor manera de plegar la izquierda que usted describe:

(v~)/(|. list) 

Es una manera muy natural, casi aplicación "literal" de la definición. El costo de revertir la lista es muy pequeño (imo).

La otra manera obvia de implementar el pliegue izquierda es fijar

new_list = (first v second) v rest 

por ejemplo:

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

manera:

- foldl >:i.9 
_43 

pero su camino realiza mucho mejor que esto tanto en el espacio como en el tiempo.

+0

Te doy el premio, aunque la respuesta de ephemient fue muy interesante, porque creo que está claro que mi solución es probablemente la mejor, aunque no puedo probarlo. –

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

No tengo idea si es más (o menos) eficiente.

+0

Es difícil de decir. Con números por debajo de 4500, tu solución y la mía son instantáneas. Después de eso, el tuyo causa un error en la pila y el mío funciona bien. Entonces, en ese sentido, el mío es más eficiente, pero aparte de los recursos, es difícil decir cuál es más rápido. –

+0

Ah, y pensé que agregaría que el tuyo es ingenioso y educativo. –

Cuestiones relacionadas