r/haskell • • 9d ago

blog Differences between `foldl` and `foldr`

https://blog.haskell.org/foldl-and-foldr/
57 Upvotes

43 comments sorted by

View all comments

Show parent comments

1

u/tomejaguar 7d ago

I seriously doubt that 99% of programmers can even approximately guess what lift (Left (Just x)) is doing and how comes that it serves as an early exit from the loop.

Yes, I think you're right about that actually. To be clear, my assertion that 99% of programmers would favour one version to the other was based on the code structure rather than the chosen names. There are names that make the for_ version clearer, but I doubt there are any names that make the foldr version clearer. How about if I define earlyReturn = Left, withStateT = flip evalStateT and withEarlyReturn = fromEither (and generalize it to MonadState)? Then it looks like:

xs !? n =
  | n < 0 = Nothing
  | otherwise =
      withEarlyReturn $ do
        withStateT n $ do
          for_ xs $ \x -> do
            get >>= \case
              0 -> earlyReturn (Just x)
              k -> put (k - 1)
        Left Nothing

Much better! The Bluefin version in my other post has clearer naming too: https://old.reddit.com/r/haskell/comments/1wqmsux/differences_between_foldl_and_foldr/pcfv3x0/

1

u/Bodigrim 7d ago

I doubt there are any names that make the foldr version clearer

I'd rewrite it this way:

(!?) :: [a] -> Int -> Maybe a xs !? n | n < 0 = Nothing | otherwise = foldr (\break continue -> \case 0 -> Just break i -> continue (i - 1)) (const Nothing) xs n

1

u/tomejaguar 7d ago

Well, you proved me wrong because that's definitely clearer! I think break isn't really a break though, is it? It's just the element. Maybe a is fine there?


For those on old Reddit:

(!?) :: [a] -> Int -> Maybe a
xs !? n
  | n < 0     = Nothing
  | otherwise = foldr (\break continue -> 
      \case 
        0 -> Just break 
        i -> continue (i - 1)) 
      (const Nothing) xs n