Fold

Fold

Intro

Module: Prelude
Function: foldl
Type: [(a -> b -> a) -> a -> b] -> a
Description: it takes the second argument and the first item of the list and applies the function to them, then feeds the function with this result and the second argument and so on. See scanl for intermediate results.
Related: foldl1, foldr, foldr1, scanl, scanl1, scanr, scanr1

Example 1

Input: foldl (/) 64 [4,2,4]

Output: 2.0

Example 2

Input: foldl (/) 3 []

Output: 3.0

https://en.wikipedia.org/wiki/Fold_(higher-order_function)

 foldl :: (b -> a -> b) -> b -> [a] -> b
 foldl f z []     = z
 foldl f z (x:xs) = foldl f (f z x) xs
             
Rust *iterator*.fold(*initval*, *func*) *iterator*.rev().fold(*initval*, *func*)        
Scala *list*.foldLeft(*initval*)(*func*) (*initval* /: *list*)(*func*) *list*.foldRight(*initval*)(*func*) (*list* :\ *initval*)(*func*)        

https://blog.csdn.net/zwvista/article/details/54747749

Map

-- 映射
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
-- map f [a, b, c, d] = f a : f b : f c : f d : []
-- 过滤
filter :: (a -> Bool) -> [a] -> [a]
filter _ []      = []
filter p (x:xs)
  | p x          = x : filter p xs
  | otherwise    =     filter p xs
-- p a==True, p b==False, p c==False, p d==True
-- filter f [a, b, c, d] = a : d : []

用fold实现map

分析:如何构造fold的函数F?

F的输入有两个a,b,输出类型为a;对于map来说,输出类型为[b]。所以F的第一个输入类型应该是[b],而第二个类型为b

-- 映射
map' :: (a -> b) -> [a] -> [b]
map' f xs       = foldr (\x acc -> (f x):acc) [] xs
-- 过滤
filter' :: (a -> Bool) -> [a] -> [a]
filter' p xs    = foldr (\x acc -> if p x then x:acc else acc) [] xs

用C++实现

// ConsoleApplication1.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include <iostream>
#include <vector>
#include <assert.h>


template <class F, class A, class B>
A foldl(F f, A a, std::vector<B> const& b)
{
	if (b.empty())
	{
		return a;
	}

	return	foldl(f, f(a, b[0]), std::vector<int>(b.begin() + 1, b.end()));
}

template <class B, class F, class A>
std::vector<B> Map(F f, std::vector<A> const& a)
{
	return	foldl(
		[f](std::vector<B> const& b2, A a2) -> std::vector<B>
	{
		auto t = b2;
		t.push_back(f(a2));
		return t;
	}
	, std::vector<B>(), a);
}

template <class F, class A>
std::vector<A> Filter(F f, std::vector<A> const& a)
{
	return	foldl(
		[f](std::vector<A> const& b2, A a2) -> std::vector<A>
	{
		auto t = b2;
		if(f(a2))
			t.push_back(a2);
		return t;
	}
	, std::vector<A>(), a);
}

void main()
{
	assert(foldl([](int a, int b) {return a + b; }, 0, std::vector<int>{ 1, 2, 3 })
		==1 + 2 + 3);

	auto t = Map<int>([](int a) {return a + 1; }, std::vector<int>{ 1, 2, 3 });

	auto t2 = Filter([](int a) {return a%2==0; }, std::vector<int>{ 1, 2, 3, 4 });
	1 + 2;
}

Point-free style

1

Point-free style means that the arguments of the function being defined are not explicitly mentioned, that the function is defined through function composition.

If you have two functions, like

square :: a -> a
square x = x*x

inc :: a -> a
inc x = x+1

and if you want to combine these two functions to one that calculates x*x+1, you can define it “point-full” like this:

f :: a -> a
f x = inc (square x)

The point-free alternative would be not to talk about the argument x:

f :: a -> a
f = inc . square

2

Haskell example:

Conventional (you specify the arguments explicitly):

sum (x:xs) = x + (sum xs)
sum [] = 0

Point-free (sum doesn’t have any explicit arguments - it’s just a fold with + starting with 0):

 sum = foldr (+) 0

Or even simpler: Instead of g(x) = f(x), you could just write g = f.

3

函数组合的另一用途就是定义 point free style (也称作 pointless style) 的函数。就拿我们之前写的函数作例子:

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

等号的两端都有个 xs。由于有柯里化 (Currying),我们可以省掉两端的 xsfoldl (+) 0 回传的就是一个取一 List 作参数的函数,我们把它修改为 sum' = foldl (+) 0,这就是 point free style。

4

下面这个函数又该如何改成 point free style 呢?

fn x = ceiling (negate (tan (cos (max 50 x))))  

像刚才那样简单去掉两端的 x 是不行的,函数定义中 x 的右边还有括号。cos (max 50) 是有错误的,你不能求一个函数的余弦。我们的解决方法就是,使用函数组合。

fn = ceiling . negate . tan . cos . max 50  

漂亮!

Ref

https://wiki.jikexueyuan.com/project/haskell-guide/high-order-function.html

Powered by Jekyll and Theme by solid

本站总访问量