zoukankan      html  css  js  c++  java
  • Haskell 笔记 ③

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

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

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

    同样的对列表的递归技巧可以手艹出takereverserepeatzip、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>:2:1-15
          (Ord a0) arising from a use of ‘it’ at <interactive>:2:1-15
          (Num a0) arising from a use of ‘it’ at <interactive>:2:1-15
    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函数:反转一个函数的两个参数,常用来flipzip函数

    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/evenelem

    其实mapfilter都能由列表表达式实现,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

    ⑥适用于二元函数的隐式递归foldlfoldr

    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表达式的参数顺序。

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

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

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

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

    ⑦ $函数

    这是一个奇怪的函数。

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

    f $ x = f x

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

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

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

    f = sum $ filter (>10) $ map (^2) [1,2,3,4]

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

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

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

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

  • 相关阅读:
    2012 金华 现场赛
    依据错误原理解决Hibernate执行出现No CurrentSessionContext configured!错误
    【python】a[::-1]翻转
    【算法】各种哈希算法
    【wireshark】打开后显示There are no interfaces on which a capture can be done
    【python】在python中调用mysql
    【mysql】执行mysql脚本
    【mysql】用navicat连接虚拟机mysql出现错误代码(10038)
    【python-mysql】在ubuntu下安装python-mysql环境
    【python】lamda表达式,map
  • 原文地址:https://www.cnblogs.com/neopenx/p/4279580.html
Copyright © 2011-2022 走看看