Pairing adjacent list items in Haskell

前端 未结 3 625
情话喂你
情话喂你 2020-12-16 00:55

I have a chained list like

[\"root\", \"foo\", \"bar\", \"blah\"]

And I\'d like to convert it to a list of tuples, using adjacent pairs. Li

3条回答
  •  情深已故
    2020-12-16 01:44

    It's possible to generalize the zipAdj in the question to work with arbitrary Traversable containers. Here's how we'd do it if we wanted the extra element on the front end:

    import Data.Traversable
    
    pairDown :: Traversable t => a -> t a -> t (a, a)
    pairDown x = snd . mapAccumL (\old new -> (new, (old,new))) x
    
    *Pairing> take 10 $ pairDown 0 [1..]
    [(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,10)]
    *Pairing> pairDown 0 [1..10]
    [(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,10)]
    

    To stick the extra element on the end, we can use mapAccumR:

    import Data.Traversable
    
    pairUp :: Traversable t => t a -> a -> t (a, a)
    pairUp xs x = snd $ mapAccumR (\old new -> (new, (new,old))) x xs
    

    This effectively traverses the container backwards.

    *Pairing> pairUp [0..10] 11
    [(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,10),(10,11)]
    *Pairing> take 10 $ pairUp [0..] undefined
    [(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,10)]
    

    It's impossible to generalize the apparently-desired function in quite this fashion, but it's possible to generalize it a bit differently:

    import Data.Foldable
    import Prelude hiding (foldr)
    
    pairAcross :: Foldable f => f a -> [(a,a)]
    pairAcross xs = foldr go (const []) xs Nothing
      where
        go next r Nothing = r (Just next)
        go next r (Just prev) = (prev, next) : r (Just next)
    

    This gives

    *Pairing> pairAcross [1..10]
    [(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,10)]
    

提交回复
热议问题