在高阶函数中,fold / reduce函数参数的名称(如果有)是什么?
我正在研究一个Monadic表格处理库,其中的行被折叠以产生简单的分析(例如查找列的最小,最大,平均值)。因此,我正在为fold
函数的参数寻找一个合理的名称,并且在ML社区(或Haskell或Common Lisp作为第二和第三候选人)中公认的任何名称都将很有趣。
类似的名称f
在fold
功能描述中很常见,但是它没有描述性,名词更适合。
fold
是高阶函数。fold的论证只是一个论点
在高阶函数中,fold / reduce函数参数的名称(如果有)是什么?
我正在研究一个Monadic表格处理库,其中的行被折叠以产生简单的分析(例如查找列的最小,最大,平均值)。因此,我正在为fold
函数的参数寻找一个合理的名称,并且在ML社区(或Haskell或Common Lisp作为第二和第三候选人)中公认的任何名称都将很有趣。
类似的名称f
在fold
功能描述中很常见,但是它没有描述性,名词更适合。
fold
是高阶函数。fold的论证只是一个论点
Answers:
如@jozefg所述,我不知道对此是否有任何答案。因此,完全出于推测,这是一种可能的解释:
我怀疑原因是因为该类型(例如(a -> b -> b)
在Haskell的foldr
类型中)比任何一个名字都有意义。由于a
and b
类型参数可以是任何东西,因此该函数还可以执行几乎所有操作。所以,你留下了类似的名字function
,combiner
,morphism
,和argument
,这是不是特别意义也不大。最好使用简短的,无干扰的名称。
另一个例子是id :: a -> a
函数:您应该如何称呼它的参数?同样,我认为id
'type'比其参数名称更具描述性。
但是,我同意您的看法-似乎应该在数学中使用通用名称。我希望有人可以对此进行纠正。
真实代码中其名称的一些示例:
在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)))))
我不同意f
“函数参数”的坏名字的想法fold
。我们在编程中要使用描述性名称的原因是,我们知道名称所描述的内容,并且该名称f
在数学(和函数式编程语言)中通常用作函数(g
和h
)。
我们几乎一无所知f
(通过设计,因为如果我们可以更详细地说明它,那么我们就不能使用fold
太多东西),这个名称f
告诉我们我们需要知道的所有内容,只是它是两个参数的函数。这个名字f
很像英语中的代词“ it”,它是一个占位符,几乎可以代表任何含义。直到我们在句子中使用它,我们才知道它是什么,f
并且直到我们打电话时,我们才知道它是什么fold
。
在命名事物时,我们希望从名称中获得尽可能多的信息,并且我们希望名称简短(如果我们可以在不牺牲重要信息的情况下获得名称)。在这里,我们有一个非常,它告诉我们近,我们知道它的一切简称。我认为无法对其进行改进。
在命令式编程中,i
用作循环计数器(如果需要,还可以像j
和一样k
);在函数式编程中,f
用于高阶函数中的函数自变量(g
和和h
,如果需要更多的话)。我对函数式语言没有足够的经验,无法确保f / g / h约定与i / j / k约定一样完善,但是如果不是,我认为应该这样(肯定是)建立在数学上)。
除了代词以外,我听说过的最常见的名称f
是- binary operation
或binary function
比它更具体的问题是它实际上可以做任何事情,这就是为什么人们坚持使用类型签名a -> b -> a
(或a -> b -> b
正确折叠)的原因。
因此,我建议您严格执行该操作,坚持使用类型签名,幸运的是,特定的类型签名确实具有一个名称:binary function
,就像a -> a
a unary operation
和a -> b
a一样unary function
,您可以调用a -> a -> a
a binary operation
和a -> b -> c
a binary function
。
binary operation
这将意味着更多a -> a -> a
,binary function
也将代表a -> b -> c
……真理必定存在于两者之间。:-)
您要求的功能有时被称为“组合功能”(例如,参见Fold上的HaskellWiki页面),但这并不足够普遍以至于将其称为标准术语。