美文网首页
Haskell笔记3

Haskell笔记3

作者: b7c9833ccf70 | 来源:发表于2018-06-19 23:14 被阅读0次

1.foldr

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

foldr函数应用在list上,它的功能就像是把list折叠起来一样,通过使用foldr,最后将list合成一个结果。它的具体过程是,它只接受一个以两个参数的函数,第二个参数作为函数的第二个输入,List中的元素均作为函数的第一个参数进行运算,在进行第一次运算后返回的结果作为下一步的函数的第二个参数。

例如

Input: foldr (+) 5 [1,2,3,4]

Output: 15

具体来看即: 4+5=9 => 3+9 =12 => 2+12 = 14 => 1+14=15

复杂的例子即:

alternative :: [Integer] -> Integer

alternative = foldr (\x y->if x< 20 then 5*x-3 + y else y) 0

alternative [1,2,3] =21

具体来看即: 3*5-3+0=12=>2*5-3+12=19=>1*5-3+19=21

2.函数参数,Maybe Type recursion

通常情况下,我们定义一个以List为参数的函数,即:

f::[Int]->[Int]

f [] = ..

f (x:xs) = ..

单数如果出于某些原因,我们希望每次提取两个元素作为参数,那么我们可以具体定义,例如,我们有encode函数和decode函数:

encode :: [Color] -> [Bit]

        encode []          = []

        encode (Red:xs)    = O:O:(encode xs)

        encode (Blue:xs)  = O:I:(encode xs)

        encode (Yellow:xs) = I:O:(encode xs)

Color类型中有三个元素,为了节约Bit起见,我们用两个Bit表达。那么在decode函数中,每次必须提取两个元素,其它不符合条件的皆为Nothing。我们有多种方法,此处介绍两种:



方案一:

decode :: [Bit] -> Maybe [Color]

decode []= Just []

decode (O:O:xs) =

  case decode xs of

    Nothing -> Nothing

    Just ys -> Just (Red:ys)

decode (O:I:xs) =

  case decode xs of

    Nothing -> Nothing

    Just ys -> Just (Blue:ys)

decode (I:O:xs) =

  case decode xs of

    Nothing -> Nothing

    Just ys -> Just (Yellow:ys)

decode _ = Nothing

列举所有可以decode为颜色的输入,然后将其decode为Color然后再翻译之后的list, 翻译后会得到一个color类型的list或者Nothing。 这里有一个问题是这个函数看起来不是那么的完整(non-exhaustive),因为我们没有列举[I,I]的情况。为了更好的说明这个函数的结构,我写出一个相对简单的decode函数:


data Bit = O | I

  deriving (Eq, Show, Enum, Bounded)

decode::[Bit]->Maybe [Bool]

decode [] = Just []

decode (I:xs) = case decode xs of

            Nothing -> Nothing

            Just bs -> Just (True:bs)

decode _ = Nothing

main::IO()

main = print (decode [I,I,I])

注意函数最后一个定义,它的意思是不管什么输入,它都将返回Nothing。

此处涉及到Haskell函数的pattern matching。 Haskell在调用函数时,会应用第一个可以调用的条件。 譬如在这个函数中, 如果我们 decode [],它会返回 Just [], 而不是 Nothing。decode的核心在 decode (I:xs)这一定义中。如果输入为I打头的list,那函数会对去掉I的list再进行decode,它会返回一个list,或者Nothing。如果是Nothing,那么原始的调用将返回Nothing,若为一个list,那么它会将这个list的append在第一个decode的结果之后即True:bs。

我们考虑decode [I,I,I]。 

decode [I,I,I] => decode [I,I]=> decode [I] => decode []

此处代表 [I,I,I] 取决于 [I,I]的结果, [I,I] 取决于 [I],[I] 取决于 []。

而又因为: Just [] -> Just True:[] -> Just True:True:[]

所以最终结果为: Just (True:bs) = Just (True:True:True:[]) = Just [True,True,True]

而如果是 decode [I,O,I] 的话:

decode [I,O,I] -> decode [O,I] == Nothing

这里在第一步我们有类型 1:xs, 所以会进入第二个case即对后面的内容进行decode。而后我们有[O,I],此时将从函数第一条开始对应O:xs类型不是[],也不是I:xs,那么就会进入最后一个定义,decode _ = Nothing。那么此时将直接进入Nothing case,返回了Nothing,原始函数取得了bs为Nothing的消息后,进入了Nothing case返回了Nothing。此类定义有一个好处就是,在第一次看到O的时候,就会终止继续迭代。


回到我们的color decode的函数中来。通过上述例子我们可以清晰的了解这个函数的结构,它列举了所有可decode的情况,然后用相同的方法进行迭代,在第一次无法进行decode的情况下就返回Nothing,终止运算。

那么我们可不可以把可decode的情况全部分开来写,然后直接写一个decode function去综合这几种情况呢?当然可以!

decode :: [Bit] -> Maybe [Color]

decode [] = Just []

decode [O,O] = Just [Red]

decode [O,I] = Just [Blue]

decode [I,O] = Just [Yellow]

decode (a:b:xs) = case decode [a,b] of

                Nothing->Nothing

                Just c -> case decode xs of

                              Nothing -> Nothing

                              Just cs -> Just (c++cs)

decode _ = Nothing

我们可以首先把几种decode的方法写出来,最后用a:b来泛指这三种情况。但是此处我们要先判断[a,b]是否可被decode即会不会有[I,I]的情况,然后再看剩余list的decode情况--进行迭代。比较神奇的是这种方式运行的结果会比上一种慢一些..



方案二:

decode :: [Bit] -> Maybe [Color]

decode []= Just []

decode (O:O:xs) = add Red (decode xs)

decode (O:I:xs) = add Blue (decode xs)

decode (I:O:xs) = add Yellow (decode xs)

decode _ = Nothing

add :: Color -> Maybe [Color] -> Maybe [Color]

add color xs =

  case xs of

    Nothing -> Nothing

    Just ys -> Just (color:ys)

这种方案更容易理解。我们需要一个辅助函数add,来把Color 和 Just [Color] 类型组成list,像“:” operator一样。 由于此时是Maybe Type,我们无法应用“:”operator,为此构建了add。剩余的则为基本迭代,decode一对然后再一对,每次的结果都返回成list。




相关文章

  • Haskell笔记3

    1.foldr foldr::(a->b->b)->b->[a]->b foldr函数应用在list上,它的功能就...

  • Haskell笔记2

    1 Polymorphic Types 在很多情况下,不同的数据类型会有相同功能的函数,例如判定相等或者不等,Li...

  • Haskell笔记4

    divide and conquer 这一部分主要是对作业中divideAndConquer的解释,因为我觉得这个...

  • Haskell笔记1

    前言 这个学期开始学习Haskelll(主要关于Codeworld和ghci),感觉很多东西和OOP不一样,最近感...

  • 函数式的宗教-00: 认识lisp(clojure)与haske

    总体大纲: lisp与haskell简单介绍 lisp与haskell应用领域 lisp与haskell技术分析 ...

  • monad以及monad的四条定理

    haskell的范畴是hask范畴(haskell的所有类型隶属于hask范畴),所以haskell的所有函子都是...

  • 01 数据类型

    swift中结构体在haskell中的描述 枚举类型在haskell中的描述 枚举携带类型在haskell中描述 ...

  • Haskell基础

    [TOC] 假设读者都有函数式编程方面的知识。这个笔记只是记录笔者觉得Haskell 最有特点的几个地方。 概念 ...

  • Haskell学习笔记(一)

    这一系列的笔记主要参考中文版的 Real World Haskell,这篇博文作为本系列的第一篇,先介绍一下Has...

  • haskell笔记(2) - funtions

    pattern matching 如果模式匹配多个值,必须用括号括起来(if you want to bind t...

网友评论

      本文标题:Haskell笔记3

      本文链接:https://www.haomeiwen.com/subject/ocnzeftx.html