将数组中所有数平方
def foo(xs): for i in range(len(xs)): xs[i] = xs[i] ** 2 return xs
foo :: [Int] -> [Int] foo xs = map (^2) xs
线性素数筛法 \(O(nloglogn)\)
def primes(n): P = [True for i in range(n+1)] for i in range(2, n+1): if P[i]: for j in range(i*i, n+1, i): P[j] = False return [i for i in range(2, n+1) if P[i]]
primes :: Int -> [Int] primes n = takeWhile (<n) (filterPrime [2..]) where filterPrime (p:xs) = p : filterPrime [x | x <- xs, x `mod` p /= 0]
求出所有小于23333的奇平方数的平方和(平方数的平方和)
int bar() { int ans = 0; int i = 0; while (i++) { if (i * i >= 23333) break; if (i * i % 2 == 1) ans += i * i * i * i; } return ans; }
oddSquareSum = (sum . map (^2) . takeWhile (<10000) . filter odd) (map (^2) [1..])
命令式编程与函数式编程的主要区别:
举例:
compose :: (a -> b) -> (b -> c) -> (a -> c) compose f g = \x -> f (g x)
flip :: (a -> b -> c) -> (b -> a -> c) flip f = \x y -> f y x
addOne :: Int -> Int addOne x = x + 1
x = input() print(x)
没有变量,没有赋值,只有绑定。
dic = {'a': 1, 'b': 1, 'c': 3} dic['b'] = 2 print(dic)
(let [m {:a 1 :b 1 :c 3}] (println (assoc m :b 2)) (println m))
函数式编程的基本概念中,没有"循环"(for, while, repeat),只有递归。
def dot(xs, ys): n = len(xs) prod = 0 for i in range(n): prod += xs[i] * ys[i] return prod
dot :: [Double] -> [Double] -> Double dot [] [] = 0.0 dot (x:xs) (y:ys) = x*y + dot xs ys
借助函数式编程工具箱:
dot xs ys = sum $ zipWith (*) xs ys
函数式编程工具箱 (functional programming toolbox): 一组函数式编程中常用的函数、工具或者思维。
将一个函数应用到列表的每个元素上,并返回由结果组成的新列表。
map (+1) [1,2,3] -- [2,3,4] map (^2) [1,2,3] -- [1,4,9] map (\x -> 2*x-1) [1,2,3] -- [1,3,5]
map :: (a -> b) -> [a] -> [b] map _ [] = [] map f (x:xs) = f x : map f xs
筛选出列表中符合条件的元素。
filter even [1,2,3,4,5] -- [2, 4] filter isPrime [1,2,3,4,5,6,7,8,9] -- [2,5,7]
filter :: (a -> Bool) -> [a] -> [a] filter _ [] = [] filter p (x:xs) | p x = x : filter xs | otherwise = filter xs
fold (+) 0 [1,2,3,4,5] -- 15
等价于
5 + 0 => 5 4 + 5 => 9 3 + 9 => 12 2 + 12 => 14 1 + 14 => 15
展开为表达式
(1 + (2 + (3 + (4 + (5 + 0)))))
foldr :: (a -> b -> b) -> b -> [a] -> b foldr _ z [] = z foldr f z (x:xs) = f x (foldr f z xs)
map f xs = foldr (\x acc -> f x : acc) [] xs
filter f xs = foldr (\x acc -> if f x then x : acc else acc) [] xs
(flip concat) "Hello," "world!" -- "world!hello,"
positives :: [Int] positives = 1 : map (+1) positives
理论依据:
[1,2,3, ...] == 1 : [1+1, 2+1, 3+1, ...] == 1 : [2, 3, 4, ...]
positives = () => [1].concat ( positives().map(x => x+1) )
不管在什么情况下调用,都会形成死循环!
take 10 positives -- [1,2,3,4,5,6,7,8,9,10] -- or even... let squares = map (^2) positives take 3 squares -- [1,4,9]
take 的实现
take :: Int -> [a] -> [a] take _ [] = [] take 0 _ = [] take n (x:xs) = x : take (n-1) xs
到底发生了什么...
take 10 positives -- note: positives = 1 : map (+1) positives == take 10 (1:map (+1) positives) == 1 : take 9 (map (+1) positives) == 1 : take 9 (map (+1) (1 : map (+1) positives)) == 1 : take 9 (2 : map (+2) positives) == 1 : 2 : take 8 (map (+2) positives) -- ... == 1:2:3:4:5:6:7:8:9:10: take 0 (map (+10) positives) == [1,2,3,4,5,6,7,8,9,10]
很多时候函数式编程看起来像一把精巧优美却华而不实的绣花剑,的确,在实际应用之中,函数式编程有一些不足与劣势。但事实上,他也具有很多命令式编程所不具备的优点。
quickSort :: [Int] -> [Int] quickSort [] = [] quicksort (x:xs) = let smaller = filter (<=x) xs larger = filter (>x) xs in quickSort smaller ++ [x] ++ quickSort larger
如果使用Lisp语言,能让程序变得多短?以Lisp和C的比较为例,我听到的大多数说法是 C代码的长度是Lisp的7倍到10倍 。但是最近,New Architect杂志上有一篇介绍ITA软件公司的文章,里面说" 一行Lisp代码相当于20行C代码 ",因为此文都是引用ITA总裁的话,所以我想这个数字来自ITA的编程实践。 如果真是这样,那么我们可以相信这句话。ITA的软件,不仅使用Lisp语言,还同时大量使用C和C++,所以这是他们的经验谈。
答案:一种计算模型。
什么是计算模型?
合法的Lambda表达式
演算规则
举个例子:
(a, b) => a + b
利用柯里化可以写成
a => (b => a + b)
Y组合子的形式
Y组合子事实上求出了函数的不动点:
不动点和递归有什么关系?
构造辅助函数
metaFact fact n = if n == 0 then 1 else n * fact (n-1)
“一个单子(Monad)说白了不过就是自函子范畴上的一个幺半群而已。”
“A monad is just a monoid in the category of endofunctors, what's the problem?”
by James Iry in Brief, Incomplete and Mostly Wrong History of Programming Languages
main :: IO () main = do putStrLn "What is your name?" name <- getLine putStrLn "Hello, " ++ name
Haskell的故事
add :: Int -> Int -> Int add x y = x + y
addOne :: Int -> Int addOne = add 1
addOne y = 1 + y
add :: Int -> (Int -> Int)
Haskell具有完备且强大的类型系统。
例子:代数数据类型
自定义列表
data List a = EmptyList | Cons a (List a)
自定义二叉树
data Tree a = EmptyTree | Node a (Tree a) (Tree a)