Skip to main content
added 405 characters in body
Source Link
Gurkenglas
  • 3.7k
  • 12
  • 17

Edit: Since we've already silently been passing pull 2 [x] into the last case, we might as well get rid of pull 1 _, which can also be handled silently, for:

pull _ []           = Nothing
pull 2 (xs:ys:yss)  = fmap (\(pl,pr) -> pl:(pr:ys):yss) (unsnoc xs)
pull n (xs:[]:xss)  = fmap (\(p:ps) -> p:[]:ps) (pull (n-1) (xs:xss))
pull n (xs:xss)     = fmap (xs:) (pull (n-1) xss)

Edit: Since we've already silently been passing pull 2 [x] into the last case, we might as well get rid of pull 1 _, which can also be handled silently, for:

pull _ []           = Nothing
pull 2 (xs:ys:yss)  = fmap (\(pl,pr) -> pl:(pr:ys):yss) (unsnoc xs)
pull n (xs:[]:xss)  = fmap (\(p:ps) -> p:[]:ps) (pull (n-1) (xs:xss))
pull n (xs:xss)     = fmap (xs:) (pull (n-1) xss)
Source Link
Gurkenglas
  • 3.7k
  • 12
  • 17

Since you only use call the nonpartial case of tlTrns and only use it once, you can inline it. Pattern matching is better than head/tail/fst/snd. Maybe's fmap can be used again.

-- | Given a 2D list, select a list via index,
-- transfer the last item  of its immediate non blank
-- left neighbour to its head.
pull :: Int           -- based 1 index
      -> [[a]]        -- 2D list
      -> Maybe [[a]]  -- result after operation
pull _ []           = Nothing                       -- empty list / out of bounds
pull 1 _            = Nothing                       -- no left neighbour
pull 2 ([]:_)       = Nothing                       -- empty left neighbour
pull 2 (xs:ys:yss)  = Just $ let (pl, pr) = splLst xs
                        in pl:(pr:ys):yss           -- base case take from left neighbour
pull n (xs:[]:xss)  = fmap (\(p:ps) -> p:[]:ps) (pull (n-1) (xs:xss))
                                                    -- carry over due to blank mid
pull n (xs:xss)     = fmap (xs:) (pull (n-1) xss)   -- recurse tail

You can make splLst nonpartial by using Maybe. Then it turns out that Data.List.Extra already implements that and calls it unsnoc. Using it, you can eliminate another case from pull.

import Data.List.Extra (unsnoc)

-- | Given a 2D list, select a list via index,
-- transfer the last item  of its immediate non blank
-- left neighbour to its head.
pull :: Int           -- based 1 index
      -> [[a]]        -- 2D list
      -> Maybe [[a]]  -- result after operation
pull _ []           = Nothing                       -- empty list / out of bounds
pull 1 _            = Nothing                       -- no left neighbour
pull 2 (xs:ys:yss)  = fmap (\(pl,pr) -> pl:(pr:ys):yss) (unsnoc xs)
                                                    -- base case take from left neighbour
pull n (xs:[]:xss)  = fmap (\(p:ps) -> p:[]:ps) (pull (n-1) (xs:xss))
                                                    -- carry over due to blank mid
pull n (xs:xss)     = fmap (xs:) (pull (n-1) xss)   -- recurse tail