Qual è il nome dell'argomento funzionale in fold


10

Nella funzione di ordine superiore piega / riduce qual è il nome dell'argomento funzionale?

Sto lavorando a una libreria di elaborazione tabulare monadica in cui le righe vengono piegate per produrre analisi semplici (come trovare il minimo, il massimo, la media di una colonna). Sto quindi cercando un nome valido per l'argomento della foldfunzione e qualsiasi nome che sia ben consolidato nella comunità ML (o Haskell o Common Lisp come secondo e terzo candidato) sarebbe interessante.

Un nome simile fè comune nella descrizione delle foldfunzioni, tuttavia è poco descrittivo e un nome sarebbe più adatto.


10
Non ce n'è uno. In effetti, non esiste nemmeno un nome universalmente usato per i catamorfismi (fold)
Daniel Gratzer,

2
Se questa è una domanda per un compito scolastico o un esame, devi ottenere la risposta dall'insegnante o dal libro di testo, non da noi. Potrebbe chiamarlo qualcosa di diverso. Ciò che viene insegnato in classe non è sempre ciò che viene comunemente usato nel mondo reale.
Robert Harvey,

7
@RobertHarvey Questa non è una domanda di esame (?) O qualcosa di simile. Come programmatore, penso che sia molto importante scegliere nomi validi per programmare oggetti (tipi, variabili, ecc.). E se qualcosa ha un nome ben noto, allora non c'è motivo di non usarlo - a parte l'ignoranza, ed è a questo che servono le domande.
user40989

9
@Izkata No, non è corretto. Una funzione di ordine superiore è una funzione che accetta una funzione. foldè una funzione di ordine superiore. L'argomento da piegare è solo questo, un argomento
Daniel Gratzer,

1
@jozefg Questo come risposta alla seconda parte del tuo commento. Per quanto riguarda la prima parte (e la domanda), vedi il mio post su Meta. Si chiamano parametri procedurali.
Izkata,

Risposte:


8

Non so se c'è una sola risposta a questo, come menzionato da @jozefg. E così puramente per speculazione, ecco una possibile spiegazione:

Sospetto che il motivo sia perché il tipo - (a -> b -> b)in Haskellfoldr , ad esempio - è più significativo di qualsiasi nome si possa inventare. Poiché i parametri ae btype potrebbero essere qualsiasi cosa , anche la funzione potrebbe fare praticamente qualsiasi cosa. Così si è lasciato con nomi come function, combiner, morphism, e argument, che non sono particolarmente significativo sia. Potrebbe anche usare un nome breve e non distratto.

Un altro esempio è la id :: a -> afunzione: come si dovrebbe chiamare il suo argomento? Ancora una volta, penso che idil tipo sia più descrittivo del nome dell'argomento.

Tuttavia, sono d'accordo con te - sembra che ci dovrebbe essere un nome comune, forse in matematica. Spero che qualcuno mi possa correggere su questo.


Alcuni esempi del suo nome in codice reale:

Nelle librerie di Haskell , viene principalmente chiamato f(e talvolta operatornei commenti):

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 ())

Si chiama anche f in 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)))))

6

Non sono d'accordo con l'idea che fsia un brutto nome per l'argomento funzione di fold. Il motivo per cui vogliamo nomi descrittivi nella programmazione è quindi sappiamo cosa descrive il nome e il nome fè comunemente usato in matematica (e linguaggi di programmazione funzionale) per una funzione (così come sono ge h).

Non sappiamo quasi nulla f(in base alla progettazione, dal momento che se potessimo essere più specifici al riguardo, non potremmo usare foldcome tante cose), e il nome fci dice tutto ciò che dobbiamo sapere, tranne che è una funzione di due argomenti. Il nome fè molto simile al pronome "it" in inglese - è un segnaposto che potrebbe significare quasi tutto. Non sappiamo cosa sia "finché" non lo usiamo in una frase e non sappiamo cosa fsia fino a quando non lo chiamiamo fold.

Quando nominiamo le cose, vogliamo ottenere quante più informazioni possibili dal nome e preferiamo che il nome sia breve (se riusciamo a ottenerlo senza sacrificare informazioni importanti). Qui, abbiamo un nome molto breve che ci dice quasi tutto ciò che sappiamo al riguardo. Non credo che possa essere migliorato.

Nella programmazione imperativa, iviene utilizzato come contatore di loop (come lo sono je k, se ne abbiamo bisogno di più); nella programmazione funzionale, fviene utilizzato per un argomento di funzione in funzioni di ordine superiore (come lo sono ge h, se ne abbiamo bisogno di più). Non ho abbastanza esperienza con i linguaggi funzionali per essere sicuro che la convenzione f / g / h sia ben consolidata come la convenzione i / j / k, ma se non lo è, penso che dovrebbe essere (sicuramente lo è stabilito in matematica).


3

Il nome più comune per questo che ho sentito diverso dal pronome fsarebbe binary operationo binary function- il problema con l'essere più specifico di quello è che potrebbe letteralmente fare qualsiasi cosa , ed è per questo che le persone si attaccano alla firma del tipo a -> b -> a(o a -> b -> bse è la piega giusta) .

Quindi ti propongo di fare esattamente questo, attenersi alla firma del tipo, per fortuna che la firma del tipo specifico ha un nome:, binary functionproprio come a -> aè a unary operation, ed a -> bè a unary function, puoi chiamare a -> a -> aa binary operatione a -> b -> ca binary function.


1
Per me binary operationsarebbe più media a -> a -> ae binary functionavrebbe resistito per a -> b -> c... la verità sicuramente sta nel mezzo. :-)
user40989

@ user40989 buona chiamata, corretta.
Jimmy Hoffa,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.