¿Cuál es el nombre del argumento funcional en fold?

10

En la función de orden superior fold / reduce ¿cuál es el nombre, si lo hay, del argumento funcional?

Estoy trabajando en una biblioteca de procesamiento tabular monádico donde las filas se pliegan para producir análisis simples (como encontrar el mínimo, máximo, promedio de una columna). Por lo tanto, estoy buscando un nombre sólido para el argumento de la foldfunción y cualquier nombre que esté bien establecido en la comunidad de ML (o Haskell o Common Lisp como segundo y tercer candidato) sería interesante.

Un nombre como fes común en la descripción de foldfunciones, sin embargo, no es descriptivo y un nombre sería más adecuado.

usuario40989
fuente
10
No hay uno De hecho, ni siquiera hay un nombre universalmente utilizado para catamorfismos (pliegue)
Daniel Gratzer
2
Si esta es una pregunta para una tarea o examen escolar, debe obtener la respuesta del maestro o del libro de texto, no de nosotros. Él puede estar llamándolo algo diferente. Lo que se enseña en un aula no siempre es lo que se usa comúnmente en el mundo real.
Robert Harvey
77
@RobertHarvey Esta no es una pregunta de examen (?) Ni nada parecido. Como programador, creo que elegir buenos nombres para programar objetos (tipos, variables, etc.) es muy importante. Y si algo tiene un nombre bien conocido, entonces no hay razón para no usarlo, aparte de la ignorancia, y para eso están las preguntas.
user40989
99
@Izkata No, eso es incorrecto. Una función de orden superior es una función que toma una función. foldEs una función de orden superior. El argumento para retirarse es solo eso, un argumento
Daniel Gratzer
1
@jozefg Eso como respuesta a la segunda parte de tu comentario. En cuanto a la primera parte (y la pregunta), vea mi publicación sobre Meta. Se llaman parámetros de procedimiento.
Izkata

Respuestas:

8

No sé si hay una sola respuesta a esto, como mencionó @jozefg. Y por pura pura especulación, aquí hay una posible explicación:

Sospecho que la razón es porque el tipo, (a -> b -> b)en Haskell'sfoldr , por ejemplo, es más significativo que cualquier nombre que se le ocurra. Dado que los parámetros ay btype podrían ser cualquier cosa , la función podría hacer casi cualquier cosa también. Así que uno se queda con nombres como function, combiner, morphism, y argument, que no son especialmente significativos tampoco. También podría usar un nombre corto y que no distraiga.

Otro ejemplo es la id :: a -> afunción: ¿cómo debe llamar a su argumento? Nuevamente, creo que idel tipo es más descriptivo que su nombre de argumento.

Sin embargo, estoy de acuerdo con usted, parece que debería haber un nombre común, tal vez en matemáticas. Espero que alguien pueda corregirme sobre esto.


Algunos ejemplos de su nombre en código real:

En las bibliotecas de Haskell , se llama principalmente f(y a veces operatoren los comentarios):

class Foldable t where
    -- | Map each element of the structure to a monoid,
    -- and combine the results.
    foldMap :: Monoid m => (a -> m) -> t a -> m
    foldMap f = foldr (mappend . f) mempty

    -- | Right-associative fold of a structure.
    --
    -- @'foldr' f z = 'Prelude.foldr' f z . 'toList'@
    foldr :: (a -> b -> b) -> b -> t a -> b
    foldr f z t = appEndo (foldMap (Endo . f) t) z

    -- | Right-associative fold of a structure, 
    -- but with strict application of the operator.
    foldr' :: (a -> b -> b) -> b -> t a -> b
    foldr' f z0 xs = foldl f' id xs z0
      where f' k x z = k $! f x z

    -- | Left-associative fold of a structure.
    --
    -- @'foldl' f z = 'Prelude.foldl' f z . 'toList'@
    foldl :: (a -> b -> a) -> a -> t b -> a
    foldl f z t = appEndo (getDual (foldMap (Dual . Endo . flip f) t)) z

    -- | Left-associative fold of a structure.
    -- but with strict application of the operator.
    --
    -- @'foldl' f z = 'List.foldl'' f z . 'toList'@
    foldl' :: (a -> b -> a) -> a -> t b -> a
    foldl' f z0 xs = foldr f' id xs z0
      where f' x k z = k $! f z x

    -- | A variant of 'foldr' that has no base case,
    -- and thus may only be applied to non-empty structures.
    --
    -- @'foldr1' f = 'Prelude.foldr1' f . 'toList'@
    foldr1 :: (a -> a -> a) -> t a -> a
    foldr1 f xs = fromMaybe (error "foldr1: empty structure")
                    (foldr mf Nothing xs)
      where
        mf x Nothing = Just x
        mf x (Just y) = Just (f x y)

    -- | A variant of 'foldl' that has no base case,
    -- and thus may only be applied to non-empty structures.
    --
    -- @'foldl1' f = 'Prelude.foldl1' f . 'toList'@
    foldl1 :: (a -> a -> a) -> t a -> a
    foldl1 f xs = fromMaybe (error "foldl1: empty structure")
                    (foldl mf Nothing xs)
      where
        mf Nothing y = Just y
        mf (Just x) y = Just (f x y)

-- instances for Prelude types

instance Foldable Maybe where
    foldr _ z Nothing = z
    foldr f z (Just x) = f x z

    foldl _ z Nothing = z
    foldl f z (Just x) = f z x

instance Ix i => Foldable (Array i) where
    foldr f z = Prelude.foldr f z . elems
    foldl f z = Prelude.foldl f z . elems
    foldr1 f = Prelude.foldr1 f . elems
    foldl1 f = Prelude.foldl1 f . elems

-- | Monadic fold over the elements of a structure,
-- associating to the right, i.e. from right to left.
foldrM :: (Foldable t, Monad m) => (a -> b -> m b) -> b -> t a -> m b
foldrM f z0 xs = foldl f' return xs z0
  where f' k x z = f x z >>= k

-- | Monadic fold over the elements of a structure,
-- associating to the left, i.e. from left to right.
foldlM :: (Foldable t, Monad m) => (a -> b -> m a) -> a -> t b -> m a
foldlM f z0 xs = foldr f' return xs z0
  where f' x k z = f z x >>= k

-- | Map each element of a structure to an action, evaluate
-- these actions from left to right, and ignore the results.
traverse_ :: (Foldable t, Applicative f) => (a -> f b) -> t a -> f ()
traverse_ f = foldr ((*>) . f) (pure ())

-- | Map each element of a structure to a monadic action, evaluate
-- these actions from left to right, and ignore the results.
mapM_ :: (Foldable t, Monad m) => (a -> m b) -> t a -> m ()
mapM_ f = foldr ((>>) . f) (return ())

También se llama f en Clojure :

(def
    ^{:arglists '([f coll] [f val coll])
      :doc "f should be a function of 2 arguments. If val is not supplied,
  returns the result of applying f to the first 2 items in coll, then
  applying f to that result and the 3rd item, etc. If coll contains no
  items, f must accept no arguments as well, and reduce returns the
  result of calling f with no arguments.  If coll has only 1 item, it
  is returned and f is not called.  If val is supplied, returns the
  result of applying f to val and the first item in coll, then
  applying f to that result and the 2nd item, etc. If coll contains no
  items, returns val and f is not called."
      :added "1.0"}    
    reduce
     (fn r
       ([f coll]
             (let [s (seq coll)]
               (if s
                 (r f (first s) (next s))
                 (f))))
       ([f val coll]
          (let [s (seq coll)]
            (if s
              (if (chunked-seq? s)
                (recur f 
                       (.reduce (chunk-first s) f val)
                       (chunk-next s))
                (recur f (f val (first s)) (next s)))
              val)))))

fuente
6

No estoy de acuerdo con la idea de que fes un mal nombre para el argumento de la función fold. La razón por la que queremos nombres descriptivos en la programación es para que sepamos lo que el nombre describe, y el nombre fse usa comúnmente en matemáticas (y lenguajes de programación funcionales) para una función (como son gy h).

No sabemos casi nada f(por diseño, ya que si pudiéramos ser más específicos al respecto, no podríamos usar foldtantas cosas), y el nombre fnos dice todo lo que necesitamos saber, excepto que es una función de dos argumentos. El nombre fes muy parecido al pronombre 'it' en inglés: es un marcador de posición que podría significar casi cualquier cosa. No sabemos qué es 'eso' hasta que lo usamos en una oración, y no sabemos qué fes hasta que lo llamamos fold.

Al nombrar cosas, queremos obtener tanta información del nombre como sea posible, y preferimos que el nombre sea corto (si podemos obtenerlo sin sacrificar información importante). Aquí, tenemos un nombre muy corto que nos dice casi todo lo que sabemos al respecto. No creo que se pueda mejorar.

En la programación imperativa, ise usa como un contador de bucles (como están jy k, si necesitamos más); en programación funcional, fse utiliza para un argumento de función en funciones de orden superior (como están gy h, si necesitamos más). No tengo suficiente experiencia con lenguajes funcionales para asegurarme de que la convención f / g / h esté tan bien establecida como la convención i / j / k, pero si no lo está, creo que debería estarlo (definitivamente es establecido en matemáticas).

Michael Shaw
fuente
3

El nombre más común para esto que he escuchado que no sea el pronombre fsería binary operationo binary function: el problema con ser más específico es que podría hacer literalmente cualquier cosa , y es por eso que las personas se adhieren a la firma de tipo a -> b -> a(o a -> b -> bsi es el pliegue correcto) .

Por lo tanto, le propongo que haga exactamente eso, se adhiera a la firma de tipo, por suerte esa firma de tipo específica tiene un nombre: binary functional igual que a -> aes a unary operation, y a -> bes a unary function, puede llamar a -> a -> aa binary operationy a -> b -> ca binary function.

Jimmy Hoffa
fuente
1
Para mí binary operationsignificaría más a -> a -> ay binary functionrepresentaría a -> b -> c... la verdad seguramente está en el medio. :-)
user40989
@ user40989 buena llamada, corregida.
Jimmy Hoffa
1

La función que solicita a veces se denomina "función de combinación" (consulte, por ejemplo, la página de HaskellWiki en Fold ), pero esto no es lo suficientemente común como para llamarla terminología estándar.

Dominique Devriese
fuente