Haskell心得(1) 模式匹配、高阶函数、组合函数
2015-07-09 09:47
253 查看
摘要:介绍了haskell的几种定义函数方式:模式匹配、高阶函数、函数组合
haskell是一种强类型的函数式编程语言。haskell里面,类型是一个核心的问题。但作为函数式编程的普遍特性,高阶函数是首先要考察的。除了高阶函数和组合函数之外,模式匹配尤其是列表的匹配是haskell的独特优点,另外point-free风格也是比较有趣的。
模式匹配是指,函数的参数有多种可能的形式,调用时自动找到匹配的形式并调用。通常只用一个小写字母表示参数而没有特殊形式的模式称为万能模式,可以匹配除了特殊形式的任意的参数。列表和元组属于haskell的基本数据结构,常在模式匹配里使用。下面的阶乘函数是一个最简单的例子。参数或者为任意正整数,或者为0。
下面是元组和列表的模式匹配。函数调用时按照元组和列表的形式选择合适的模式。
下面是定义函数的一些特殊形式,包括哨位(guard)、where、let、case。guard可以使函数在满足不同条件时得到不同的值,这些条件以“|”区分。case类似,实际上case就是模式匹配。where和let是函数定义时局部作用域中绑定变量或者函数。
下面的例子是定义快速排序函数。
这两个表达式是等效的。另外还有一种重要的符号“.”表示函数组合。简洁的表达了将一个函数调用后的值传递给另一个函数作为参数。
最后举个例子来说明point-free风格。
注:本文代码示例大部分来自《haskell趣学指南》。
haskell是一种强类型的函数式编程语言。haskell里面,类型是一个核心的问题。但作为函数式编程的普遍特性,高阶函数是首先要考察的。除了高阶函数和组合函数之外,模式匹配尤其是列表的匹配是haskell的独特优点,另外point-free风格也是比较有趣的。
模式匹配是指,函数的参数有多种可能的形式,调用时自动找到匹配的形式并调用。通常只用一个小写字母表示参数而没有特殊形式的模式称为万能模式,可以匹配除了特殊形式的任意的参数。列表和元组属于haskell的基本数据结构,常在模式匹配里使用。下面的阶乘函数是一个最简单的例子。参数或者为任意正整数,或者为0。
factorial :: Int -> Int factorial 0 = 1 factorial n = n * factorial (n-1)
下面是元组和列表的模式匹配。函数调用时按照元组和列表的形式选择合适的模式。
addX :: (Double, Double) -> (Double, Double) -> Double addX (x1, _) (x2, _) = x1 + y1
length' :: [a] -> Int length' [] = 0 length' (x:[]) = 1 length' (x:xs) = 1 + length' xs
下面是定义函数的一些特殊形式,包括哨位(guard)、where、let、case。guard可以使函数在满足不同条件时得到不同的值,这些条件以“|”区分。case类似,实际上case就是模式匹配。where和let是函数定义时局部作用域中绑定变量或者函数。
max' :: (Ord a) => a -> a -> a max' a b | a < = b | otherwise = a
addF :: [a] -> [a] -> a addF s1 s2 = f1 + f2 where (f1:_) = s1 (f2:_) = s2
areaC :: Double -> Double areaC x = let square = x * x in pi * square
find' :: [(Double, Double)] -> [Double] find' xs = [xsi | (x1, x2) <- xs, let xsi = x1 * x2, xsi < 100]
head' :: [a] -> a head' xs = case xs of [] -> error "empty" (x:_) -> x
下面的例子是定义快速排序函数。
quicksort :: (Ord a) => [a] -> [a] quicksort [] = [] quicksort (x:xs) = let small = [a | a <- xs, a <= x] large = [a | a<- xs, a> x] in quicksort small ++ [x] ++ quicksort large高阶函数是函数式编程必不可少的特性。跟scheme一样,最常用的就是map、filter、foldr、foldl等。它们将集合视为整体,强调的是对集合的整体操作,而屏蔽了循环迭代等在数据结构的微观层面上的操作。
map :: (a -> b) -> [a] -> [b] map _ [] =[] map f (x:xs) = f x : map f fs
filter :: (a -> bool) -> [a] -> [a] filter _ [] = [] filter p (x:xs) | p x = x : filter p xs | otherwise = filter p xs
foldl :: (a -> b -> b) -> b -> [a] -> b foldl f b0 [] = b0 foldl f b0 (x:xs) = foldl f (f x b0) xs
foldr :: (a -> b -> b) -> b -> [a] -> b foldr f b0 [] = b0 foldr f b0 (x:xs) = f x (foldr f b0 xs)haskell有一些特殊形式可以简化函数的表达。例如$符号,其实就是改变左结合的函数调用为右结合。
($) :: (a -> b) -> a -> b f $ x = f x
sum (filter (> 10) (map (*2) [1..10])) sum $ filter (> 10) $ map (*2) [1..10]
这两个表达式是等效的。另外还有一种重要的符号“.”表示函数组合。简洁的表达了将一个函数调用后的值传递给另一个函数作为参数。
(.) :: (b -> c) -> (a -> b) -> (a -> c) f . g = \x -> f (g x)
replicate 2 (product (map (*3) (zipWith max [1,2] [4,5]))) replicate 2 . product . map (*3) $ zipWith max [1,2] [4,5]这也是两种等效的写法。
最后举个例子来说明point-free风格。
sum' :: (Num a) => [a] -> a sum' xs = foldl (+) 0 xs
sum' = foldl (+) 0上下两种sum'的写法是等同的,唯一的区别是省略了xs这个参数。结合“$”和“.”,free-point能使代码更简洁,更关注于代码的逻辑抽象本身,而非针对数据的具体操作过程。
注:本文代码示例大部分来自《haskell趣学指南》。
相关文章推荐
- Linux智能小开关rfkill
- 对话框程序SW_HIDE 和 SW_MINIMIZE 区别
- 使用jquery-mockjax模拟ajax请求做前台测试
- 【CODE】js转换时间格式:将时间转换成自己想要的格式
- 列表页模板 常识
- R语言的帮助使用和图形功能简介
- 怎样知道linux是否安装了mysql
- 新建组
- Android手势操作
- UIWebView用法详解及代码分享
- 2015必看的开源APP源码
- new/malloc 分配二维数组存储空间
- 使用vmware虚拟机快速克隆CentOS
- asp.net 获取进程。。杀到进程
- 升级xcode 一句话解决xcode插件失效问题
- UML时序图(2)
- Java之美[从菜鸟到高手演变]之HashMap、HashTable
- I2C上拉电阻取值问题
- HashMap实现原理以及与其他Map实现类的区别
- NHibernate初学二之简单执行SQL及HQL、Linq