Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.8k views
in Technique[技术] by (71.8m points)

haskell - Take elements on even positions from the list

Problem: using fold, take from the list elements which are on the even positions:

GHCi> evenOnly [1..10]
 [2,4,6,8,10]
GHCi> evenOnly ['a'..'z']
 "bdfhjlnprtvxz"

evenOnly :: [a] -> [a]
evenOnly = undefined

I decided at first to get a list of alternating 0-es and 1-s: [0,1,0,1..]

Prelude> let g = iterate (x -> (x + 1) `mod` 2) 0
Prelude> take 10 $ g
[0,1,0,1,0,1,0,1,0,1]

Then zip it with the original list, getting a list of pairs: [(x1, 0), (x2,1), (x3,0) .. (xn, ?)]:

Prelude> zip g [1,2,3,4,5]
[(0,1),(1,2),(0,3),(1,4),(0,5)]

After that, foldr the list of pairs with a filtering function and an empty list as initialization value.

So I thought that this would work:

evenOnly :: [a] -> [a]
evenOnly xs = let g = iterate (x -> (x + 1) `mod` 2) 0
  in
  foldr ( (x, n) s -> if n == 1 then x : s else s) [] . (zip g xs)

But it gives an error, that I don't understand:

foldr.hs:44:59: error:
    ? Couldn't match expected type ‘a0 -> t0 (a1, Integer)’
                  with actual type ‘[(Integer, a)]’
    ? Possible cause: ‘zip’ is applied to too many arguments
      In the second argument of ‘(.)’, namely ‘(zip g xs)’
      In the expression:
        foldr ( (x, n) s -> if n == 1 then x : s else s) [] . (zip g xs)
      In the expression:
        let g = iterate ( x -> (x + 1) `mod` 2) 0
        in
          foldr ( (x, n) s -> if n == 1 then x : s else s) [] . (zip g xs)
    ? Relevant bindings include
        xs :: [a] (bound at foldr.hs:42:10)
        evenOnly :: [a] -> [a] (bound at foldr.hs:42:1)

I think my idea is correct, I just did something wrong with the syntax.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

(.) is function composition but zip g xs is a list not a function. You can just apply the resulting list as the argument to foldr directly. Note you have the arguments g and xs in the wrong order:

evenOnly :: [a] -> [a]
evenOnly xs = let g = iterate (x -> (x + 1) `mod` 2) 0
  in
  foldr ( (x, n) s -> if n == 1 then x : s else s) [] (zip xs g)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...