简体   繁体   English

Haskell Foldl实现与文件夹

[英]Haskell foldl implementation with foldr

I have troubles understanding the implementation of the foldl function using foldr . foldl理解使用foldr实现的foldl功能。 I have read this question ( Writing foldl using foldr ) and I still have some things I don't understand in the following example: 我已经读过这个问题( 使用foldr编写foldl ),但是在下面的示例中,我仍然有些不了解的事情:

fun :: [Int] -> [Int]
fun l = foldr g (const []) l 1
    where g x f lst = if gcd x lst == 1 then x : f x else f lst

The function takes a list as parameter and return another list where gcd(l[i], l[i + 1] = 1 . 该函数将一个列表作为参数,并返回另一个列表,其中gcd(l[i], l[i + 1] = 1

My questions are the following: 我的问题如下:
1. Who are x , f and lst 1. xflst是谁
2. What is const[] and why I can't use the id function? 2.什么是const[] ,为什么我不能使用id函数?

foldr is one of those weird tools like bicycles that are really easy to use once you get the hang of them but hard to learn from the start. foldr是诸如自行车之类的怪异工具之一,一旦掌握了它,它们确实很容易使用,但从一开始就很难学习。 After several years of experience, I've gotten really good at spotting problems I can solve with foldr , and solving them with it immediately and correctly, but it could easily take me a while to figure out what just what I've done in enough detail to explain! 经过几年的经验,我非常擅长发现我可以用foldr解决的问题,并立即正确地解决了这些问题,但是我很容易花点时间来弄清楚自己已经做了什么详细解释!

From a practical standpoint, I usually think of foldr in vaguely continuation-passing language. 从实际的角度来看,我通常会用模糊连续传递语言来考虑文件foldr Ignoring the "simple" case where foldr is only applied to three arguments, an application of foldr looks like this: 忽略这里的“简单”的情况下foldr仅适用于三个参数,一个应用foldr看起来是这样的:

foldr go finish xs acc1 acc2 ... where
  finish acc1 acc2 ... = ?
  go x cont acc1 acc2 ... = ?

acc1 , etc., are accumulators passed "from left to right". acc1等是“从左到右”传递的累加器。 The result consists, conceptually, of a single value passed "from right to left". 从概念上讲,结果由“从右到左”传递的单个值组成。

finish gets the final values of the accumulators and produces something of the result type. finish获得累加器的最终值并产生某种结果类型。 It's usually the easiest part to write because 这通常是最容易编写的部分,因为

foldr go finish [] acc1 acc2 ...
=
finish acc1 acc2 ...

So once you figure out just what you want your fold to produce, writing finish is fairly mechanical. 所以一旦你找出你希望你的折叠产生正是,写作finish是比较呆板。

go gets a single container element, a "continuation", and the accumulators. go获得一个容器元素,一个“ continuation”和一个累加器。 It passes modified values if those accumulators "forward" to the continuation to get a result, and uses that result to construct its own. 如果这些累加器“前进”到延续以获取结果,它将通过修改后的值,并使用该结果构造自己的结果。

foldl is a particularly simple case because its go function just returns the result it gets from folding the rest of the container with a new accumulator argument. foldl是一种特别简单的情况,因为它的go函数仅返回通过使用新的accumulator参数折叠其余容器得到的结果。 I think it's a bit more instructive to look at an example that does a bit more. 我认为看一个例子多做点启发。 Here's one that takes a container of numbers and produces a list of pairs representing a running sum and a running product. 这是一个带有数字容器并产生代表连续和和连续乘积的对的列表。

sumsProducts :: (Num n, Foldable f) => f n -> [(n, n)]
sumsProducts xs = foldr go finish xs 0 1
  where
    finish total prod = [(total, prod)]
    go x cont total prod =
      (total, prod) : cont (x + total) (x * prod) 

foldr 's type signature is this foldr的类型签名是这个

foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

This means your foldr applied to its 3 arguments must return a function that takes the 1 as an argument. 这意味着应用于其3个参数的文件foldr必须返回一个以1作为参数的函数。

So you can specialise your foldr to this 因此,您可以将文件foldr专门用于此

foldr :: (Int -> (Int -> [Int]) -> (Int -> [Int])) 
        -> (Int -> [Int]) 
        -> [Int]
        -> (Int -> [Int])

This means your g function must have the following type 这意味着您的g函数必须具有以下类型

g :: Int -> (Int -> [Int]) -> Int -> [Int] 

So your parameters have the type 所以您的参数具有类型

x   :: Int
f    :: Int -> [Int]
lst :: Int

And foldr in its 2nd argument requires a Int -> [Int] instead of just an Int , so you can't pass it the value [] . 并且foldr在其第二个参数中需要一个Int -> [Int]而不是一个Int ,因此您不能将其值[]传递给它。

Fortunately const returns a function that ignores its argument and just always return a constant expression 幸运的是const返回的函数会忽略其参数,而总是返回常量表达式

const [] :: a -> [b]

In your case f is indeed some kind of accumulator. 就您而言, f确实是某种累加器。 But instead of reducing eg a list of values to some number, you are chaining functions here. 但是,您不是在这里将值列表减少到某个数字,而是在这里链接函数。 By passing 1 to this function chain in the end, it gets evaluated and is then building the actual list you return in fun . 最后,通过将1传递给此功能链,它会得到评估,然后构建您返回的实际列表fun

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM