Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell “foldr”和“foldl”能否相互定义?_Haskell_Fold_Foldable - Fatal编程技术网

Haskell “foldr”和“foldl”能否相互定义?

Haskell “foldr”和“foldl”能否相互定义?,haskell,fold,foldable,Haskell,Fold,Foldable,foldr和foldl可以相互定义吗 Hutton用Haskell编程说 我们需要手动定义什么?的实例的最小完整定义 Foldable类用于定义foldMap或foldr,因为类中的所有其他函数都可以派生 使用默认定义和列表实例从这两个列表中选择一个 那么如何用foldr来定义foldl 是否可以根据foldl定义foldr,以便我们可以通过定义foldl来定义可折叠的类型 为什么在Foldable中,foldMap是根据folddr定义的,而在list Foldable中,foldl的一些专门

foldr
foldl
可以相互定义吗

Hutton用Haskell编程说

我们需要手动定义什么?的实例的最小完整定义
Foldable
类用于定义
foldMap
foldr
,因为类中的所有其他函数都可以派生 使用默认定义和列表实例从这两个列表中选择一个

那么如何用
foldr
来定义
foldl

是否可以根据
foldl
定义
foldr
,以便我们可以通过定义
foldl
来定义
可折叠的
类型

为什么在
Foldable
中,
foldMap
是根据
folddr
定义的,而在list Foldable中,
foldl
的一些专门化是根据
foldl
定义的:

maximum :: Ord a => [a] -> a
maximum = foldl max

minimum :: Ord a => [a] -> a
minimum = foldl min

sum :: Num a => [a] -> a
sum = foldl (+) 0

product :: Num a => [a] -> a
product = foldl (*) 1
??它们可以改写为

maximum :: Ord a => [a] -> a
maximum = foldr max

minimum :: Ord a => [a] -> a
minimum = foldr min

sum :: Num a => [a] -> a
sum = foldr (+) 0

product :: Num a => [a] -> a
product = foldr (*) 1
谢谢

编辑2:

还有另一种方法可以满足(基于)for
foldl

foldl f a list = (foldr construct (\acc -> acc) list) a
  where
    construct x r = \acc -> r (f acc x)
编辑1

翻转函数的参数不会创建相同的foldr/foldl,这意味着此示例不满足foldr foldl的等式:

foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
foldl
在foldr方面:

foldl' :: Foldable t => (b -> a -> b) -> b -> t a -> b
foldl' f b = foldr (flip f) b 
foldr

foldr' :: Foldable t => (a -> b -> b) -> b -> t a -> b
foldr' f b = foldl (flip f) b 
反之则不然,因为foldr可能在无限列表上工作,而foldl变体永远无法做到这一点。然而,对于有限列表,虽然在过程中失去了惰性,但foldr也可以用foldl来编写。(欲了解更多信息)

Ando也不满足以下示例:

foldr (-) 2 [8,10] = 8 - (10 - 2) == 0

foldl (flip (-)) 2 [8,10] = (flip (-) (flip (-) 2 8) 10) == 4
一般来说,
foldr
foldl
都不能相互实现。
Foldable
的核心操作是
foldMap
,所有其他操作都可以从中派生出来。
foldr
foldl
都不够。然而,这种差异只在无限或(部分)未定义结构的情况下才会显现出来,因此有一种倾向是掩盖这一事实

@Damianaltenero已经展示了
foldl
foldr
的“实现”相互之间的关系:

foldl' c = foldr (flip c)
foldr' c = foldl (flip c)
但他们并不总是有正确的行为。考虑列表。然后,
foldr(:)[]xs=xs
用于所有
xs::[a]
。但是,对于所有的
xs
,都是
foldr'(:)[]/=xs
,因为
foldr'(:)[]xs=foldl(flip(:)nxs
)和
foldl
(在列表的情况下)必须遍历列表的整个脊椎才能生成输出。但是,如果
xs
是无限的,
foldl
无法遍历整个无限列表,因此
foldr'(:)[]xs
将永远循环无限
xs
,而
foldr(:)[]xs
只生成
xs
<但是,代码>foldl'=foldl
根据需要。本质上,对于
[]
foldr
是“自然的”,而
foldl
是“非自然的”。用
foldr
实现
foldl
是有效的,因为你正在失去“自然性”,但就
foldl
而言,实现
foldr
是无效的,因为你无法恢复那种“自然”行为

另一方面,考虑一下

data Tsil a = Lin | Snoc (Tsil a) a
-- backwards version of data [a] = [] | (:) a [a]
在这种情况下,
foldl
是自然的:

foldl c n Lin = n
foldl c n (Snoc xs x) = c (foldl c n xs) x
而且
foldr
是不自然的:

foldr c = foldl (flip c)
现在,
foldl
在无限/部分未定义的
Tsil
s上具有良好的“生产性”行为,而
foldr
没有。用
foldl
实现
foldr
是可行的(正如我刚才所做的那样),但是你不能用
foldr
实现
foldl
,因为你无法恢复生产力

foldMap
避免了此问题。对于
[]

foldMap f [] = mempty
foldMap f (x : xs) = f x <> foldMap f xs
-- foldMap f = foldr (\x r -> f x <> r) mempty
现在,

文档中实际给出了
foldl
foldr
的实现

foldr f z t = appEndo (foldMap (Endo . f) t ) z
foldl f z t = appEndo (getDual (foldMap (Dual . Endo . flip f) t)) z
f
用于将
ta
中的每个
a
转换为
b->b
Endo b
),然后将所有
b->b
组合在一起(
foldr
以一种方式组合,而
foldl
Dual(Endo b)
向后组合)最后的
b->b
应用于初始值
z::b

由于性能原因,
实例可折叠[]
中的专门化
总和
最小值
等中的
折页
替换为
折页
。我们的想法是,你无论如何都不能对无限列表求和(这个假设是错误的,但它通常是正确的),所以我们不需要foldr来处理它。在某些情况下,使用
foldl
foldr
更有效,因此
foldr
更改为
foldl
。对于
Tsil
,我希望
foldr
有时比
foldl
性能更好,因此
sum
minimum
等可以按照
foldr
重新实现,而不是
fold
,以获得性能改进。请注意,文档中指出,
sum
minimum
等应等同于使用
foldMap
/
fold
的表单,但可能定义较少,这正是可能发生的情况


有点像附录,但我认为值得注意的是:

genFoldr c n [] = n; genFoldr c n (x : xs) = c x (genFoldr c n xs)
instance Foldable [] where
  foldl c = genFoldr (flip c)
  foldr c = foldl (flip c)
-- similarly for Tsil
实际上是一个有效、合法的可折叠实例,其中
foldr
foldl
都是不自然的,都不能处理无限结构(
foldMap
默认为
foldr
,因此也不会处理无限列表)。在这种情况下,
foldr
foldl
可以相互书写(
foldl c=foldr(flip c)foldMap (: []) xs = xs -- even for infinite xs
foldMap (Snoc Lin) xs = xs -- even for infinite xs
foldr f z t = appEndo (foldMap (Endo . f) t ) z
foldl f z t = appEndo (getDual (foldMap (Dual . Endo . flip f) t)) z
genFoldr c n [] = n; genFoldr c n (x : xs) = c x (genFoldr c n xs)
instance Foldable [] where
  foldl c = genFoldr (flip c)
  foldr c = foldl (flip c)
-- similarly for Tsil
instance Foldable [] where
  foldr = genFoldr
  foldl c = foldr (flip c)
foldl f a l = foldr (\b e c -> e (f c b)) id l a
import Data.Functor.Reverse
import Data.Monoid

data DL a = DL [a] (Reverse [] a)
  deriving Foldable
instance Foldable DL where
  foldMap f (DL front rear) = foldMap f front <> foldMap f rear
  foldMap f (DL front rear) = foldMap f front <> getDual (foldMap (Dual . f) (getReverse rear))
  foldr c n (DL xs (Reverse ys)) =
    foldr c (foldl (flip c) n ys) xs
  foldl f b (DL xs (Reverse ys)) =
    foldr (flip f) (foldl f b xs) ys