Qual é o nome do argumento funcional na dobra

10

Na função de ordem superior, dobre / reduza qual é o nome, se houver, do argumento funcional?

Estou trabalhando em uma biblioteca de processamento tabular monádico onde as linhas são dobradas para produzir análises simples (como encontrar a média mínima, máxima e média de uma coluna). Estou, portanto, procurando um nome sólido para o argumento da foldfunção e qualquer nome que esteja bem estabelecido na comunidade de ML (ou Haskell ou Common Lisp como segundo e terceiro candidatos) seria interessante.

Um nome como fé comum na descrição de foldfunções, porém é descritivo e um substantivo seria mais adequado.

user40989
fonte
10
Não existe um. Na verdade, não é ainda um nome universalmente utilizado para catamorphisms (dobrar)
Daniel Gratzer
2
Se essa é uma pergunta para um trabalho ou exame da escola, você precisa obter a resposta do professor ou do livro, e não de nós. Ele pode estar chamando isso de algo diferente. O que é ensinado em sala de aula nem sempre é o que é comumente usado no mundo real.
Robert Harvey
7
@RobertHarvey Esta não é uma pergunta do exame (?) Ou qualquer outra coisa semelhante. Como programador, acho que escolher bons nomes para objetos de programação (tipos, variáveis ​​etc.) é muito importante. E se algo tem um nome bem conhecido, não há razão para não usá-lo - além da ignorância, e é para isso que servem as perguntas.
user40989
9
@ Izkata Não, isso está incorreto. Uma função de ordem superior é uma função que assume uma função. foldé uma função de ordem superior. O argumento para desistir é apenas isso, um argumento
Daniel Gratzer 20/12/2013
1
@jozefg Isso como resposta à segunda parte do seu comentário. Quanto à primeira parte (e à pergunta), veja meu post no Meta. Eles são chamados de parâmetros processuais.
Izkata

Respostas:

8

Não sei se há uma resposta única para isso, como o @jozefg mencionou. E tão puramente por especulação, aqui está uma explicação possível:

Eu suspeito que o motivo é porque o tipo - (a -> b -> b)no de Haskellfoldr , por exemplo - é mais significativo do que qualquer nome que alguém possa inventar. Como os parâmetros ae btype podem ser qualquer coisa , a função também pode fazer praticamente qualquer coisa. Então, você é deixado com nomes como function, combiner, morphism, e argument, que não são especialmente significativo tanto. É melhor usar um nome curto e não distraído.

Outro exemplo é a id :: a -> afunção: como você deve chamar esse argumento? Mais uma vez, acho que ido tipo é mais descritivo do que o nome do argumento.

No entanto, eu concordo com você - parece que deveria haver um nome comum, talvez em matemática. Espero que alguém possa me corrigir nisso.


Alguns exemplos de seu nome em código real:

Nas bibliotecas de Haskell , é chamado principalmente f(e às vezes operatornos comentários):

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

Também é chamado f em 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)))))

fonte
6

Eu discordo da idéia de que fé um nome ruim para o argumento da função fold. A razão pela qual queremos nomes descritivos na programação é para sabermos o que o nome descreve, e o nome fé comumente usado em matemática (e linguagens de programação funcionais) para uma função (como são ge h).

Não sabemos quase nada sobre isso f(por design, pois se pudéssemos ser mais específicos sobre o assunto, não poderíamos usá-lo foldem tantas coisas), e o nome fnos diz tudo o que precisamos saber, exceto que é uma função de dois argumentos. O nome fé muito parecido com o pronome 'it' em inglês - é um espaço reservado que pode significar quase qualquer coisa. Nós não sabemos o que é 'até usá-lo em uma frase e não sabemos o que fé até chamarmos fold.

Ao nomear coisas, queremos obter o máximo possível de informações do nome e preferimos que o nome seja curto (se conseguirmos isso sem sacrificar informações importantes). Aqui, temos um nome muito curto que nos diz quase tudo o que sabemos sobre ele. Eu não acho que isso possa ser melhorado.

Na programação imperativa, ié usado como um contador de loop (como são je k, se precisarmos de mais); na programação funcional, fé usado para um argumento de função em funções de ordem superior (como são ge h, se precisarmos de mais). Não tenho experiência suficiente com linguagens funcionais para garantir que a convenção f / g / h seja tão bem estabelecida quanto a convenção i / j / k, mas se não for, acho que deveria ser (definitivamente é estabelecido em matemática).

Michael Shaw
fonte
3

O nome mais comum para isso que já ouvi falar que fnão seja o pronome seria binary operationou binary function- o problema de ser mais específico do que isso é poderia fazer literalmente qualquer coisa , e é por isso que as pessoas mantêm a assinatura de tipo a -> b -> a(ou a -> b -> bse estiver dobra à direita) .

Então, proponho que você faça exatamente isso, atenha-se à assinatura de tipo, felizmente essa assinatura de tipo específica tem um nome:, binary functionassim como a -> aé a unary operation, e a -> bé a unary function, você pode chamar a -> a -> aa binary operatione a -> b -> ca binary function.

Jimmy Hoffa
fonte
1
Para mim binary operation, mais significaria a -> a -> ae binary functionrepresentaria a -> b -> c... a verdade certamente está no meio. :-)
user40989 31/01
@ user40989 boa ligação, corrigida.
Jimmy Hoffa
1

A função que você solicita às vezes é chamada de "função combinada" (veja, por exemplo, a página do HaskellWiki no Fold ), mas isso não é suficientemente comum para chamar de terminologia padrão.

Dominique Devriese
fonte