①循环?NO!请递归思考问题!

手艹一个求列表中最大值代码,C语言中习惯性for扫一下比较出最大值。但是可以用递归!

maximum'::(Ord a)=>[a]->a
maximum' []=error "empty!"
maximum' [x]=x
maximum' (x:xs) = max x (maximum' xs) 

同样的对列表的递归技巧可以手艹出take、reverse、repeat、zip、elem

rev::[a]->[a]
rev []=[]
rev (x:xs)=rev xs++[x] //后端插入用++
zip'::[a]->[b]->[(a,b)]
zip' [] _=[]
zip' _ []=[]
zip' (x:xs) (y:ys)=[(x,y)]++zip' xs ys

甚至是一个低效率的快排(递归扫了两遍数据,没有左右推进效率高)

qsort:: (Ord a) =>[a]->[a]
qsort []=[]
qsort (key:xs) = let left=[x|x<-xs,x<=key]
right=[x|x<-xs,x>key]
in qsort left ++ [key] ++ qsort right

注意一下Haskell中的命名方式,大写字母不可以作为首字母(目测这样是为了推广  首单词小写-剩余单词大写   这种命名方式)

QuickSort是错误的,quickSort才是理想的命名方式 (参照Qt的库)

②函数作为函数的参数?

看起来有点不可思议,这其实是Haskell的一大亮点,在Haskell中,函数的参数是逐个取的,而不是像C语言那样一次取完。

如 Three x y z=x*y*z,先取x,再取y,计算x*y,再取z,用前面x*y的结果*z

慢着,这不就是递归么,递归又递归,递归还是递归。难怪有人吐槽,Haskell就是递归!

函数嵌套时,可以用这种特性减少参数的书写,让你的代码看起来更吊。(好难改=。=)

如f x=compare x 100,可以改写成f compare 100

这样就衍生一种叫“截断”的用法,可以copy一个中缀函数的功能,如+、-(例外)、*、/

如copy “/”,divTen = (/10), subTen = (-10)是不行的,-10会被当成数值,可以用库的subtract函数,这么写subTen=subtract 10

③2333,为什么我之前写的函数在Console运行时,都给了警告?

你会看见一坨屎一样的东西

Defaulting the following constraint(s) to type ‘Integer’
(Show a0) arising from a use of ‘print’ at <interactive>::-
(Ord a0) arising from a use of ‘it’ at <interactive>::-
(Num a0) arising from a use of ‘it’ at <interactive>::-
In a stmt of an interactive GHCi command: print it

原因是console只能输出字符串,要显示必须调用show函数,console为了显示自动帮我们加了,然后很无耻地给了一个警告,其实这和我们有半毛钱关系啊?

④当函数作为参数之后...

手艹zipWith函数:参数是一个二参一回的函数f、两个列表,分别取列表扔到f里,结果存到一个列表中。

zipWith'::(a->b->c)->[a]->[b]->[c]
zipWith' _ [] _ =[]
zipWith' _ _ []=[]
zipWith' f (x:xs) (y:ys)=f x y:zipWith' f xs ys

需要注意的是函数作为参数时,类型的写法,一定要把这个函数的类型声明给完整写出来。

有许多二参一回函数:+、max/min,++,符号作为函数时,要用(),如(+)才是函数

手艹flip函数:反转一个函数的两个参数,常用来flip掉zip函数

flip'::(a->b->c)->b->a->c
flip' f x y = f y x

手艹map函数: 将一个一参一回函数作用于一个列表。

map'::(a->b)->[a]->[b]
map' _ []=[]
map' f (x:xs)=f x:map' f xs

如(+3)、(++ “fuck!”)

手艹filter函数: 从一个列表中抽取符合谓词(布尔)条件的新列表

filter'::(a->Bool)->[a]->[a]
filter' _ []=[]
filter' p (x:xs)
|p x==True =x:filter' p xs
|otherwise =filter' p xs

如 (>3)、odd/even、elem

其实map和filter都能由列表表达式实现,2333,不过用函数看起来吊吊的。

⑤lambda表达式

lambda表达式不是什么稀奇东西,就是个匿名(起名字好麻烦)的单行函数

如三个数相加,普通写成  addThree x y z=x+y+z

lambda表达式就是  addThree= (\x y z->x+y+z)

由参数区和函数区两部分构成,”\“起手,“->”隔开,好处嵌套不要重新外部写一个函数了

当然有更极端的推导写法:\x->\y->\z->x+y+z,阐述了lambda递归调用参数的事实。

那么addThree=\x y z=z+y+x 这样写就会报错了,addThree x y z=z+y+x却是对的。

Lambda表达式虽然简单,但是参数的使用必须严格按照参数顺序。

当然,lambda的类型推导还是得和原来一样标出来的。addThree::Int->Int->Int->Int

⑥适用于二元函数的隐式递归foldl、foldr

fold函数三个参数:函数、初始值、列表,其中初始值+列表=凑出二元式子

fold分为左折叠和右折叠,区别是左折叠初始(累计)值作为左操作数,并且从列表左边取值,而右折叠则作为右操作数,从列表右边取值。

手艹sum函数(左折叠)(fold折叠的函数无须写类型推导)

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

由于操作符无顺序,所以左右折叠都行。

手艹map函数(右折叠、左折叠)

map'::(a->b)->[a]->[b]
map' f xs=foldr (\x acc->f x:acc) [] xs
map'::(a->b)->[a]->[b]
map' f xs=foldl (\acc x->acc++[f x]) [] xs

注意观察一下左右操作数的变化以及lambda表达式的参数顺序。

由于”:”的效率好于”++”,所以生成列表通常使用右折叠。

简化版:foldl1、foldr1(是数字1),无须传入初始值,很方便,但是无法处理空列表,如手艹maximum

maximum'::(Ord a)=>[a]->a
maximum'= foldl1 max

Debug版:scanl、scanr,追踪fold的过程,产生含有n+1元素的执行过程列表

⑦ $函数

这是一个奇怪的函数。

($)::(a->b)->a->b

f $ x = f x

你会觉得它什么也没干。其实它做了一件伟大的事,它挡在f前面多跑了一步。

所以配上$函数之后,那个函数的优先级就被降低了(挡枪的$)

$可以用来去括号,因为是右结合函数,所以只要把优先级高的函数往右边写,然后不停用$就可以全程不写难看的括号了(C语言的括号写多了,整个代码就和屎一样)

f = sum $ filter (>) $ map (^) [,,,]

执行顺序(平方->map->filter->sum),没有括号一身清。

$结合map,可以用来投射一组一元函数,到一个对象上。

f = map ($ ) [(+),(*),(-),(^)]

结果是[5,9,1,9]。

Haskell 笔记 ③的更多相关文章

  1. Haskell 笔记(三)类型系统

    类型 (Type) Haskell的类型系统式静态类型系统,在编译的时候就知道数据类型,所以不同类型的值运算在编译的时候就会报错,比如用布尔值和整数运算,在C语言中这种运算就不会报错. Haskell ...

  2. Haskell 笔记(四)函数系统

    函数系统 函数式编程当然少不了函数系统啦,在教程最初的时候就有一个最简单的函数,函数系统贯穿在Haskell全部,Haskell的函数有几个重要的性质. 首先声明一下函数的参数和返回值类型 然后有一个 ...

  3. haskell笔记1

    haskell platform下载:https://www.haskell.org/platform/ 进入haskell控制台,终端输入 $ ghci 编译文件 :l file.hs 数组操作 & ...

  4. Haskell 笔记 ②

    ①如何写一个求阶层函数? fac 0 =1 fac n=n*fac(n-1) 函数自适应匹配参数,可以把特判情况写在前面,注意按顺序匹配的,n这种万能情况写在最前面就完蛋了.同时你也注意到,函数只能一 ...

  5. Haskell 笔记 ①

    ①一切都是函数,包括常量.表达式,格式:名字 参数1 参数2.. =函数内容 ②if语句(else绝对不可以省略) F=if (..) then x else y ③没有数组,只有列表[1,2,3,4 ...

  6. haskell笔记2

    模式匹配 # haskell_test.hs length' :: [a] -> a length' [] = 0 length' (_:x) = 1 + length' x as模式 xs@x ...

  7. Haskell复习笔记(一)

    Haskell笔记这是第三次总结,前两次都因为各种原因丢失了,对于Haskell我算不上什么大神,只不过在大学时为了学习算法时选择了Haskell. 当时的入门书籍选择的是<Learn You ...

  8. haskell学习笔记_函数

    一开始学习函数式编程语言就被告知函数式编程语言是一种“定义式”的语言,而不是一种命令式的语言,在学习haskell的函数语法时,此感觉更加强烈,haskell的函数定义倾向于一种类似C++里面的swi ...

  9. Haskell语言学习笔记(88)语言扩展(1)

    ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...

随机推荐

  1. SQL跨项目查询语法

    EXEC sp_addlinkedserver 'ITSV', '', 'SQLOLEDB', '192.168.1.248' EXEC sp_addlinkedsrvlogin 'ITSV', 'f ...

  2. Hibernate的ORM原理和实现

    >>Hibernate和ORM ORM的全称是Object Relational Mapping,即对象关系映射.它的实现思想就是将关系数据库中表的数据映射成为对象,以对象的形式展现,这样 ...

  3. .net学习之母版页执行顺序、jsonp跨域请求原理、IsPostBack原理、服务器端控件按钮Button点击时的过程、缓存、IHttpModule 过滤器

    1.WebForm使用母版页后执行的顺序是先执行子页面中的Page_Load,再执行母版页中的Page_Load,请求是先生成母版页的控件树,然后将子页面生成的控件树填充到母版页中,最后输出 2.We ...

  4. 手机的ROM,RAM是各自存放什么?所谓“运行内存”和“机身内存”究竟有什么区别?

    手机的内存分为运行内存(RAM)和非运行内存(也叫机身内存.储存空间.ROM) 1.手机的内存,分为存储内存和运行内存,相当于电脑的硬盘和内存条.2.存储内存分为机身内存和存储卡.3.rom是存储内存 ...

  5. 【翻译七】java-同步

    Synchronization Threads communicate primarily by sharing access to fields and the objects reference ...

  6. HDU 5900 QSC and Master 区间DP

    QSC and Master Problem Description   Every school has some legends, Northeastern University is the s ...

  7. Activity活动

    自定义一个类继承Activity类后结构已经很好了 提供了finish()来销毁活动 要记得注册

  8. 通信原理实践(一)——音频信号处理

    一.信号的离散化 1.采样定理: –如果信号是带限的,并且采样频率fs超过信号最高频率的两倍,那么,原来的连续信号可以从采样样本中完全重建出来. 因此在仿真过程中,采样率(fs)是一个非常重要的参数. ...

  9. TextView展开和收回

    第一步:接口请求返回数据 第二步:使用handler和textview.getLineCount方法判断是否超过指定行数: community_desc_more.setVisibility(View ...

  10. android如何实现文件按时间先后顺序排列显示

    <span style="font-size:18px;">File[] files =parentFile.listFiles(fileFilter);//通过fil ...