Как называется функциональный аргумент в сгибе

10

В функции более высокого порядка сложите / уменьшите, как называется функциональный аргумент, если он есть?

Я работаю над библиотекой монадической табличной обработки, где строки складываются, чтобы произвести простой анализ (например, найти минимум, максимум, среднее для столбца). Поэтому я ищу надежное имя для аргумента foldфункции, и любое имя, хорошо известное в сообществе ML (или Haskell или Common Lisp в качестве второго и третьего кандидатов), было бы интересно.

Подобное имя fчасто встречается в описании foldфункций, однако оно не является описательным , и существительное подойдет лучше.

user40989
источник
10
Там нет ни одного. На самом деле, нет даже универсально используемого названия для катаморфизмов (сгиб)
Даниэль Гратцер
2
Если это вопрос для школьного задания или экзамена, вы должны получить ответ от учителя или учебника, а не от нас. Возможно, он называет это чем-то другим. То, чему учат в классе, не всегда то, что обычно используется в реальном мире.
Роберт Харви
7
@RobertHarvey Это не экзаменационный вопрос (?) Или что-то подобное. Как программист, я думаю, что выбор хороших имен для программирования объектов (типов, переменных и т. Д.) Очень важен. И если у кого-то есть хорошо известное имя, то нет причин не использовать его, кроме невежества, и для этого есть вопросы.
user40989
9
@Izkata Нет, это неправильно. Функция более высокого порядка - это функция, которая принимает функцию. foldявляется функцией более высокого порядка. Аргумент «сбросить» - это просто аргумент
Даниэль Гратцер,
1
@jozefg Это как ответ на вторую часть вашего комментария. Что касается первой части (и вопроса), см. Мой пост на Meta. Они называются процедурными параметрами.
Изката

Ответы:

8

Я не знаю, есть ли один ответ на это, как упоминал @jozefg. И так чисто из предположений, вот одно из возможных объяснений:

Я подозреваю, что причина в том, что тип - например, (a -> b -> b)в Haskellfoldr - более значим, чем любое имя, которое можно придумать. Поскольку параметры aи bтипа могут быть любыми , функция может делать практически все что угодно. Таким образом , вы остались с такими именами , как function, combiner, morphismи argument, которые не являются особенно значимыми либо. Можно также использовать короткое, не отвлекающее имя.

Другой пример - id :: a -> aфункция: как назвать ее аргумент? Опять же, я думаю, что idтип является более описательным, чем его имя аргумента.

Тем не менее, я согласен с вами - кажется, должно быть общее имя, возможно, в математике. Я надеюсь, что кто-то может исправить меня в этом.


Некоторые примеры его названия в реальном коде:

В библиотеках Haskell это в основном называется f(и иногда operatorв комментариях):

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

Это также называется f в 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

Я не согласен с идеей, что fэто плохое имя для аргумента функции fold. Причина, по которой нам нужны описательные имена в программировании, заключается в том, что мы знаем, что описывает это имя, и имя fобычно используется в математике (и функциональных языках программирования) для функции (как есть gи h).

Мы почти ничего не знаем f(по замыслу, так как, если бы мы могли быть более конкретными по этому поводу, мы не могли бы использовать foldстолько же вещей), и имя fговорит нам обо всем, что нам нужно знать, за исключением того, что оно является функцией двух аргументов. Название fочень похоже на местоимение «it» в английском языке - это заполнитель, который может означать почти все. Мы не знаем, что это такое, пока не используем его в предложении, и мы не знаем, что fэто, пока не позвоним fold.

При именовании вещей мы хотим получить как можно больше информации из имени и предпочитаем, чтобы имя было коротким (если мы можем получить это, не жертвуя важной информацией). Здесь у нас есть очень короткое имя, которое говорит нам почти все, что мы знаем об этом. Я не думаю, что это может быть улучшено.

В императивном программировании iиспользуется как счетчик циклов (как есть jи k, если нам нужно больше); в функциональном программировании, fиспользуется для аргумента функции в функциях высшего порядка (как есть gи h, если нам нужно больше). У меня нет достаточного опыта работы с функциональными языками, чтобы быть уверенным, что соглашение f / g / h так же хорошо, как и соглашение i / j / k, но если это не так, я думаю, что это должно быть (это определенно установлено в математике).

Майкл Шоу
источник
3

Самым распространенным названием для этого, которое я слышал, кроме местоимения, fбыло бы binary operationили binary function- проблема с более точным указанием того, что он может делать буквально все что угодно , и именно поэтому люди придерживаются сигнатуры типа a -> b -> a(или, a -> b -> bесли она правильная, складывается) ,

Поэтому я предлагаю вам сделать именно это, придерживаясь сигнатуры типа, к счастью, у сигнатуры конкретного типа есть имя: binary functionточно так же, как a -> aи a unary operation, и a -> ba unary function, вы можете вызывать a -> a -> aa binary operationи a -> b -> ca binary function.

Джимми Хоффа
источник
1
Мне binary operationбы больше , средний a -> a -> aи binary functionбудет стоять за a -> b -> c... правду , несомненно , лежит между ними. :-)
user40989
@ user40989 хороший звонок, исправлено.
Джимми Хоффа
1

Запрашиваемую вами функцию иногда называют «объединяющей функцией» (см., Например, страницу HaskellWiki в Fold ), но это не достаточно распространено, чтобы называть ее стандартной терминологией.

Доминик Девриз
источник