Lambdas和折叠(左和右)

时间:2015-12-08 15:19:17

标签: haskell lambda functional-programming

我真的不懂代码

extent = [xbins.min(), xbins.max(), ybins.min(), ybins.max()]

fig, ax = plt.subplots()
mesh = ax.imshow(values, extent=extent, origin='lower', aspect='auto',
                 cmap='gist_earth', norm=LogNorm())

ax.axis('tight')
ax.set(title='Log Normalized Plot of Values')
fig.colorbar(mesh)

plt.show()

以防:

  • 空映射到[]< ---- accumulator
  • id映射到fID(func id)
  • x是xs(list)
  • 的第一个元素

我可以排序/更改agruments“id xs []”的位置吗?

myReverse'' :: [a] -> [a]
myReverse'' xs = foldr (\x fId empty -> fId (x : empty)) id xs []

我昨天读了一本书http://learnyouahaskell.com/higher-order-functions#lambdas

myReverse'' xs = foldr (\x fId empty -> fId (x : empty)) xs id []

这个解释对我来说是可以理解的。

  

左侧折叠的二元函数将累加器作为第一个参数,将当前值作为第二个参数(所以\ acc x - > ...)

或者我可以写为

elem' :: (Eq a) => a -> [a] -> Bool  
elem' y ys = foldl (\acc x -> if x == y then True else acc) False ys  

任何人,可以帮助/指导/解释我吗?
非常感谢!

3 个答案:

答案 0 :(得分:1)

关键是如何使用差异列表。让我们写一些明确的转换:

revCons

请注意{{1}}有三个参数,虽然它的签名实际上只表示两个:差异列表实际上是一个函数类型,但您可以将这些函数视为具体列表的抽象优化表示。

答案 1 :(得分:1)

我喜欢理解这些“带有foldr的反向列表”问题的方法是将其拆分成几部分,然后应用"Foldr is made of monoids"的课程。别担心,这并不像听起来那么可怕。

首先,让我们注意reverse可以这样实现:

my_reverse xs = foldl (flip (:)) xs []

这是我们问题的第一个简化:如果我们能够弄清楚如何用foldl来编写foldr,那么我们可以将该解决方案插入my_reverse并完成用它。

现在,foldr的标准类型签名是:

foldr :: (a -> r -> r) -> r -> [a] -> r

但是参数的顺序并不重要,所以让我们以这种方式重新排列事物(也抛出一些隐含的括号),然后我们将它与map进行比较:

my_foldr :: (a -> (r -> r)) -> [a] -> (r -> r)
map      :: (a -> b       ) -> [a] -> [b]

一旦看到这封信,就不难发现我们可以这样写my_foldr

my_foldr :: (a -> (r -> r)) -> [a] -> (r -> r)
my_foldr f as = compose (map f as)
  where compose :: [r -> r] -> (r -> r)
        compose = foldr (.) id

以下列方式考虑这个问题:

  1. map操作正在将列表的每个元素转换为我们应用于r值的转换的“步骤”。
  2. compose函数使用结果列表“步骤”并使用.运算符将它们连接在一起。
  3. 现在的诀窍是我们可以用一个小小的变化来编写foldl对应物:

    my_foldl :: (a -> (r -> r)) -> [a] -> (r -> r)
    my_foldl f as = compose (map f as)
        where compose :: [r -> r] -> (r -> r)
              compose = foldr (flip (.)) id
    
    {- Example:
    >>>  my_foldl (:) [1..3] []
    [3,2,1]
    -}
    

    我所做的就是将(.)更改为flip (.)!请注意my_foldl是根据mapfoldr写的......但map也可以用foldr重写:

    my_map :: (a -> b) -> [a] -> [b]
    my_map f = foldr (\a bs -> f a : bs) []
    

    因此,我们最终得到的解决方案与您尝试理解的解决方案不同且更长,但希望它具有启发性。

答案 2 :(得分:0)

如果你这样做:

Prelude :t \x fId empty -> fId (x : empty)

你会得到:

\x fId empty -> fId (x : empty) :: a -> ([a] -> t) -> [a] -> t

此处的此功能类型相当于:

a -> ([a] -> t) -> ([a] -> t) 

表示一个函数(二元函数),它接受两个参数(第二个参数是一个函数,即[a] -> t)并返回一个函数(即[a] -> t)。

这个二元函数匹配foldr所取的第一个参数(即a -> b -> b)。

换句话说,foldr (\x fId empty -> fId (x : empty))有两个参数:一个函数和一个列表,并返回一个函数。

Prelude> :t foldr (\x fId empty -> fId (x : empty))
foldr (\x fId empty -> fId (x : empty))
  :: ([a] -> t) -> [a] -> [a] -> t

举个例子:foldr (\x fId empty -> fId (x : empty)) id [1, 2, 3]

步骤1:将3id作为参数传递给匿名二进制函数。像\empty -> id (3 : empty)这样的函数将作为新的累加器值返回。

第2步:将2\empty -> id (3 : empty)传递给匿名二进制函数。并返回\empty -> id (3 : (2 : empty))

步骤3:将1\empty -> id (3 : (2 : empty))传递给匿名二进制函数。并返回\empty -> id (3 : (2 : (1 : empty)))

因此foldr (\x fId empty -> fId (x : empty)) id [1, 2, 3]会产生类似\empty -> id (3 : (2 : (1 : empty)))的函数。

如果您将\empty -> id (3 : (2 : (1 : empty)))应用于[],那么它会为您提供[3, 2, 1]

这意味着foldr (\x fId empty -> fId (x : empty)) id [1, 2, 3] []会产生[3, 2, 1]