美文网首页
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

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