注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

HT·生活

123

 
 
 

日志

 
 

Haskell进阶  

2015-12-21 15:22:20|  分类: 函数式编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
  1. 计算模型

    看起来计算模型这个名词比较高端实际上就是pyhon里面的map reduce filter等函数,用法几乎一模一样,这种编程模型最大的特点是原子函数被作为参数

    映射 map

    最简单的一个例子,我们可以将一个正数列表中所有元素都加倍,其实我们前面已经写过了,可以用列表概括,也可以递归


    -- 列表概括

    double :: [Int] -> [Int]

    double xs = [2*x | x <- xs]

     

    -- 函数递归

    double [] = []

    double (x:xs) = 2*x : double xs

     

    -- map的原型函数

    map :: (a -> b) -> [a] -> [b]

     

    如果说用map映射的话,可以定义一个原子函数

    -- 原子函数

    double :: Int -> Int

    double x = 2*x

     

    map double list -- list就是输入的参数

     

    过滤 filter

    关于filter的用法,也是类似于map的,这里给出两个例子,filter的实现也是既可以用递归,也可以用列表概括

    -- 递归

    filter p [] = []

    filter p (x:xs)

    | p x = x :filter p xs

    | otherwise = filter p xs

    --列表概括

    filter p xs = [ x | x <- xs, p x]

     

    原子函数定义

    -- 原子函数

    isEven :: Int -> Bool

    isEven n = (n `mod` 2 == 0)

     

    positive :: Int -> Bool

    positive n = (n > 0)

     

    在filter中,函数原型

    --filter 函数原型

    filter :: (a -> Bool) -> [a] -> [a]

     

    求解list中所有的偶数

    求解list中所有的大于0的正数

    filter isEven list -- 求解list中所有偶数

    filter positive list -- 求解list中所有正数

     

     

    折叠 foldr

    对应的就是reduce函数

    常用的两个折叠函数 foldr1 和foldr

    先看看定义区别

    --折叠函数

    -- foldr1 定义

    foldr1 :: (a -> a -> a) -> [a] -> a

    -- 第一个是函数,输入有两个,比如关于Int上的(+)

    -- 第二个是列表,最后一个是输出,比如

    foldr1 (+) [3, 2, 1] -- 结果就是 6

     

    -- foldr 定义

    foldr :: (a -> a -> a) -> a ->[a] -> a --和上面最大的区别就是有了初始值,第2个参数

    -- 递归定义

    foldr f s [] = s

    foldr f s (x:xs)= f x (foldr f s xs)

    -- 理论上来说 foldr1 foldr的特殊形式,也就是说s = 0或者是True等等

    关于foldr的用法

    -- 关于foldr的用法 foldr func ini list

    -- func是函数 ini表示当list为空的时候初始值 listfoldr参数列表

    -- 1 -> n 的平方和

    sumSqrt :: Int -> Int

    sumSqrt n = foldr (+) 0 (map square [1..n])

    -- list中大于0的整数的平方和

    sumPos :: [Int] -> Int

    sumPos list = foldr (+) 0 (map square (filter positive list))

     

     

    拆分

    需要和zip结合使用,这个暂时没有研究

     

  2. 函数复合

    这里的函数复合类似于高等数学里面的函数复合,haskell中用的关键字也是一样的"."

    对于任意函数f和g,f . g可以表示为

    (f .g) x = f (g x)

    相当于输入是x,然后g作用于x,然后通过f映射为函数值,也就是输出。但是,并不是任意的f和g都能复合,必须g的输出和f的输入类型是一样的

     

    在haskell中,函数复合是从从右往左读入信息流的

     

    返回函数值

    在c/java/python等语言中,函数是可以作为返回值的,同理在haskell中也是如此

    首先用复合运算看一些定义

    -- f是原子函数

    twice f = (f . f) -- twice函数的定义将f在输入上应用两次

    -- succ是取输入的下一个值,比如succ n 返回 n + 1

    -- 如此而言

    (twice succ) 12 -- 返回的结果就是 14

    -- 上面的一句其实是等价于 succ . succ

    -- Prelude其实有一个内置的函数 iter可以自动将函数复合指定次数

    -- iter定义

    iter :: Int -> (a -> a) -> (a -> a)

     

    iter :: n f

    | n > 0 = f . iter (n-1) f

    | otherwise = id --表示空什么都不做

     

    -- 举个例子

    iter n double 1 -- 相当于把 (double 1) 复合n次,也就是2^n

     

    定义函数表达式

    如何才能返回函数呢?看下面的一个例子

    -- 输入n,输出是一个函数

    addNum :: [Int] -> (Int -> Int)

    addNum n = addN

    where

    addN m = n + m --m是返回函数的输入

     

    更简单的Lambda记法,其实就是类似于python的lambda函数

    --关于addN我们可以简单写为

    \m -> n + m -- 这是lambda函数的写法

    -- 箭头左边是输入参数,右边是输出结果

    -- 所以addNum可以写成

    addNum n = (\m -> n + m)

     

    实例

    图中,有两个函数,f和g,首先f先作用于输入x,y 然后通过g给出输出

    所以

    -- comp2的严格定义

    comp2 :: (a -> b) -> (b -> b ->) -> (a -> a ->c)

    -- 第一个输入是f,第二个输入是g, 最后是合成函数

    --等价于

    comp2 f g = (\x y -> g (f x) (f y))

    --应用

    comp2 sq add 3 4 -- 该用法的就是将 34的平方相加

     

    --另外,由于lambda隐函数的作用

    f x y x = result

    --

    \x y z -> result --的作用是完全一样的

     

    下面看几个高级一点儿的例子

    multiply :: Int -> Int -> Int

    multiply x y = x * y

     

    doubleAll :: [Int] -> [Int]

    doubleAll xs = map (multiply 2) xs

     

    member :: String -> Char -> Bool

    member xs x = elem x xs

     

     

    -- unit test

    -- data

    nums = [1,5, (-2),7] :: [Int]

    whitespace = "\t\n" :: String

    str = "hello world \n \t base \n I am \t OK!"

     

    -- for member test

    testMember :: (String -> String) -- 过滤掉whitespace里面的内i

    -- 返回的是函数

    --testMember = filter (not . (member whitespace))

    testMember = filter (\x -> not (elem x whitespace))

     

    testOpt :: ([Int] -> [Int])

    testOpt = filter (>0) . map (+1) -- 先加上1然后过滤掉小于0的元素

     

    -- for doubleAll test

    testDoubleAll :: [Int]

    testDoubleAll = doubleAll nums

  评论这张
 
阅读(158)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017