Intenté aprender F # pero me confundí al intentar distinguir entre plegar y reducir . Fold parece hacer lo mismo pero toma un parámetro adicional. ¿Existe una razón legítima para que existan estas dos funciones o están allí para dar cabida a personas de diferentes orígenes? (Por ejemplo: cadena y cadena en C #)
Aquí hay un fragmento de código copiado de la muestra:
let sumAList list =
List.reduce (fun acc elem -> acc + elem) list
let sumAFoldingList list =
List.fold (fun acc elem -> acc + elem) 0 list
printfn "Are these two the same? %A "
(sumAList [2; 4; 10] = sumAFoldingList [2; 4; 10])
f#
functional-programming
reduce
fold
Wallace
fuente
fuente
fold f a l
se puede escribir comoreduce f a::l
.fold
en términos dereduce
es más complicado que eso - ¡el tipo de acumulador defold
no tiene que ser el mismo que el tipo de cosas en la lista!Respuestas:
Fold
toma un valor inicial explícito para el acumulador mientrasreduce
usa el primer elemento de la lista de entrada como valor inicial del acumulador.Esto significa que el acumulador y, por lo tanto, el tipo de resultado deben coincidir con el tipo de elemento de la lista, mientras que pueden diferir
fold
porque el acumulador se proporciona por separado. Esto se refleja en los tipos:Además,
reduce
lanza una excepción en una lista de entrada vacía.fuente
fold
, simplemente puede agregar ese valor inicial al comienzo de la lista yreduce
¿ hacerlo ? ¿Qué sentido tienefold
entonces?'state -> 'a -> 'state
para pliegue vs'a -> 'a -> 'a
para reducir, por lo que reducir restringe el tipo de resultado para que sea el mismo que el tipo de elemento. Vea la respuesta de Tomas Petricek a continuación.Además de lo que dijo Lee, puede definir
reduce
en términos defold
, pero no (fácilmente) al revés:El hecho de que
fold
tome un valor inicial explícito para el acumulador también significa que el resultado de lafold
función puede tener un tipo diferente al tipo de valores en la lista. Por ejemplo, puede usar un acumulador de tipostring
para concatenar todos los números de una lista en una representación textual:Cuando se usa
reduce
, el tipo de acumulador es el mismo que el tipo de valores en la lista; esto significa que si tiene una lista de números, el resultado tendrá que ser un número. Para implementar la muestra anterior,string
primero tendría que convertir los números a y luego acumular:fuente
fold' & its ability to express
reducir '. Algunos idiomas tienen un concepto de quiralidad estructural (Haskell, te estoy mirando) que puedes doblar hacia la izquierda o hacia la derecha representado visualmente en esta wiki ( en.wikipedia.org/wiki/Fold_%28higher-order_function ). Con una construcción de identidad, los otros dos operadores FP "fundamentales" (filter y fmap) también se pueden implementar con una construcción de lenguaje de primera clase "fold" existente (todas son construcciones isomorfas). ( cs.nott.ac.uk/~pszgmh/fold.pdf ) Ver: HoTT, Princeton (Esta sección de comentarios es demasiado pequeña para contener ...)Veamos sus firmas:
Hay algunas diferencias importantes:
reduce
funciona solo con un tipo de elementos, los elementos de lista y acumuladorfold
pueden ser de diferentes tipos.Con
reduce
, aplicas una funciónf
a cada elemento de la lista empezando por el primero:f (... (f i0 i1) i2 ...) iN
.Con
fold
, se aplicaf
partiendo del acumuladors
:f (... (f s i0) i1 ...) iN
.Por lo tanto,
reduce
da como resultado unaArgumentException
lista vacía. Además,fold
es más genérico quereduce
; que puede utilizarfold
para implementarreduce
fácilmente.En algunos casos, el uso
reduce
es más sucinto:o más conveniente si no hay ningún acumulador razonable:
En general,
fold
es más potente con un acumulador de tipo arbitrario:fuente
fold
es una función mucho más valiosa quereduce
. Puede definir muchas funciones diferentes en términos defold
.reduce
es solo un subconjunto defold
.Definición de pliegue:
Ejemplos de funciones definidas en términos de pliegue:
fuente
fold
diferente deList.fold
como el tipo deList.fold
es('a -> 'b -> 'a) -> 'a -> 'b list -> 'a
, pero en su caso('a -> 'b -> 'b) -> 'b -> 'a list -> 'b
. Solo para hacerlo explícito. Además, su implementación de append es incorrecta. Funcionaría si le agregas un enlace, por ejemploList.collect id (fold (fun x y -> x :: y) [] [xs;ys])
, o reemplazas cons con el operador append. Por lo tanto, adjuntar no es el mejor ejemplo de esta lista.