①循环?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 笔记 ③的更多相关文章
-
Haskell 笔记(三)类型系统
类型 (Type) Haskell的类型系统式静态类型系统,在编译的时候就知道数据类型,所以不同类型的值运算在编译的时候就会报错,比如用布尔值和整数运算,在C语言中这种运算就不会报错. Haskell ...
-
Haskell 笔记(四)函数系统
函数系统 函数式编程当然少不了函数系统啦,在教程最初的时候就有一个最简单的函数,函数系统贯穿在Haskell全部,Haskell的函数有几个重要的性质. 首先声明一下函数的参数和返回值类型 然后有一个 ...
-
haskell笔记1
haskell platform下载:https://www.haskell.org/platform/ 进入haskell控制台,终端输入 $ ghci 编译文件 :l file.hs 数组操作 & ...
-
Haskell 笔记 ②
①如何写一个求阶层函数? fac 0 =1 fac n=n*fac(n-1) 函数自适应匹配参数,可以把特判情况写在前面,注意按顺序匹配的,n这种万能情况写在最前面就完蛋了.同时你也注意到,函数只能一 ...
-
Haskell 笔记 ①
①一切都是函数,包括常量.表达式,格式:名字 参数1 参数2.. =函数内容 ②if语句(else绝对不可以省略) F=if (..) then x else y ③没有数组,只有列表[1,2,3,4 ...
-
haskell笔记2
模式匹配 # haskell_test.hs length' :: [a] -> a length' [] = 0 length' (_:x) = 1 + length' x as模式 xs@x ...
-
Haskell复习笔记(一)
Haskell笔记这是第三次总结,前两次都因为各种原因丢失了,对于Haskell我算不上什么大神,只不过在大学时为了学习算法时选择了Haskell. 当时的入门书籍选择的是<Learn You ...
-
haskell学习笔记_函数
一开始学习函数式编程语言就被告知函数式编程语言是一种“定义式”的语言,而不是一种命令式的语言,在学习haskell的函数语法时,此感觉更加强烈,haskell的函数定义倾向于一种类似C++里面的swi ...
-
Haskell语言学习笔记(88)语言扩展(1)
ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...
随机推荐
-
Angularjs学习笔记9_JSON和JSONP
说到AJAX就会不可避免的面临两个问题,第一个是AJAX以何种格式来交换数据?第二个是跨域的需求如何解决?数据可以用自定义字符串或者用XML来描述,跨域可以通过服务器端代理来解决.最被推崇或者说首选的 ...
-
WebApi传参总动员(四)
前文介绍了Form Data 形式传参,本文介绍json传参. WebApi及Model: public class ValuesController : ApiController { [HttpP ...
-
关于eclipse中maven项目的问题
问题1: 严重: Error configuring application listener of class org.springframework.web.context.ContextLoad ...
-
weapon制作武器
weapon制作武器 (weapon.pas/c/cpp) 解题报告 制作武器weapon.pas/c/cpp) 背景 WZland的紧急避难所很快就建好了,WZland的居民们陆续地来到这个紧急避难 ...
-
【树形动态规划】【CTSC1997】选课 解题报告
CTSC1997-选课 描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修了这 ...
-
Android使用ViewFlipper实现左右滑动效果面
在我的博客中,上次是使用ViewPager实现左右滑动的效果的,请看文章:Android使用ViewPager实现左右滑动效果. 这次我来使用ViewFlipper实现这种效果,好了,先看看效果吧: ...
-
《JAVA与模式》之简单工厂模式
在阎宏博士的<JAVA与模式>一书中开头是这样描述简单工厂模式的:简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式.简单工厂模式是由一个工厂 ...
-
什么是CAS机制?(转)
围绕下面四个点展开叙述: 一:什么是CAS机制? 二:Java当中CAS的底层实现 三:CAS的ABA问题和解决方法 四:java8对CAS的优化 一:什么是CAS机制? 我们先看一段代码: 启动两个 ...
-
Nginx 配置文件解析
nginx 整理 nginx 配置主要是分为4个部分 1.main 全局设置2.server 主机设置 -- 指定主机与端口3.upstream 负载均衡服务器设置 -- 反向代理设置:4.locat ...
-
ELK学习笔记之F5利用EELK进行应用数据挖掘系列(2)-DNS
0x00 概述 很多客户使用GTM/DNS为企业业务提供动态智能解析,解决应用就近性访问.优选问题.对于已经实施多数据中心双活的客户,则会使用GSLB提供双活流量调度.DNS作为企业业务访问的指路者, ...