Haskell心得(1) 模式匹配、高阶函数、组合函数

原创 2015年07月09日 09:47:20

摘要:介绍了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趣学指南》。







相关文章推荐

Haskell语言学习笔记(3)map, filter, fold

map filter foldl foldr的递归实现 以及用foldr实现map filter foldl
  • zwvista
  • zwvista
  • 2017年01月26日 23:08
  • 488

Haskell笔记 (五) 高阶函数

了解高阶函数 高阶函数是Haskell的重要性质,同时也是所有函数式语言的共同性质,高阶函数实际上就是函数的函数,就是把某个函数作为另一个函数的参数的形式,就是高阶函数。 还是来看个例子吧, ...
  • ygrx
  • ygrx
  • 2013年07月16日 08:54
  • 2456

Haskell 笔记(二)List和元组

最简单的函数 函数式编程,首先要有函数吧,来看一个最简单的函数,第一个是函数名,后面是输入变量,表达式是输出 doubleMe x=x+x Haskell的函数没有return...
  • ygrx
  • ygrx
  • 2013年07月12日 16:22
  • 4005

Haskell学习——类型

Haskell一大特色就是静态类型检查,
  • pyyaoer
  • pyyaoer
  • 2014年06月15日 00:47
  • 1967

Haskell学习——语法

Haskell是以表达式为主的语言,纯函数
  • pyyaoer
  • pyyaoer
  • 2014年06月16日 09:38
  • 4987

Haskell map

source: https://www.hackerrank.com/challenges/30-dictionaries-and-maps -- Enter your code here. Re...

「学习总结-Haskell-6」Haskell 重要编程模式——Functor,Applicative,Monad

Haskell 重要编程模式——Functor,Applicative Functor,Monad Table of Contents 1 Haskell 基本知识2 Haskell ...
  • on_1y
  • on_1y
  • 2013年02月05日 20:40
  • 6850

「学习总结-Haskell-5」Haskell 重要概念——函数

Haskell 重要概念——函数 Table of Contents 1 Haskell 基本知识2 Haskell 重要数据结构-List3 Haskell 常用数据结构4 Hask...
  • on_1y
  • on_1y
  • 2013年02月04日 20:50
  • 5578

haskell排序的操作

注意处理相同的元素 1快排 qsort []=[] qsort (h:t)=(qsort(filter (h) t)) num (h:t)=filter (==h) (h:t) ...

Haskell学习——函数

作为函数式语言,Haskell的
  • pyyaoer
  • pyyaoer
  • 2014年06月15日 19:24
  • 4269
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Haskell心得(1) 模式匹配、高阶函数、组合函数
举报原因:
原因补充:

(最多只允许输入30个字)