*Main> :t text
  :: (Selectable s, StringLike str, Ord str) => s -> Scraper str str

I need to perform "second level" fmap operation:

*Main> let z = fmap (fmap (:[])) text
*Main> :t z
z :: (Selectable s, StringLike a, Ord a) => s -> Scraper a [a]

On one hand z follows API structure, but otherwise I find such code hard to read. It feels like programming against stack-based machine.

  • \$\begingroup\$ In a word: yes. This stuff comes up more than you might think. If you’re nesting them 3 or more layers deep, maybe reconsider, but 2 levels is not uncommon at all. \$\endgroup\$ – Alexis King Jan 6 '17 at 18:22
  • 1
    \$\begingroup\$ You can write it (fmap . fmap) (:[]) text, or ((.) . fmap) text to point at that level of fmap being the instance for functions. \$\endgroup\$ – Gurkenglas Jan 6 '17 at 19:06
  • 2
    \$\begingroup\$ The current question title, which states your concerns about the code, applies to too many questions on this site to be useful. The site standard is for the title to simply state the task accomplished by the code. Please see How to Ask for examples, and revise the title accordingly. \$\endgroup\$ – Jamal Jan 7 '17 at 20:01

Sometimes you can wrap the "nested functors" in a newtype which is itself a functor, use a single fmap on the newtype, and unwrap. In your case:

import Data.Functor.Compose

let z = getCompose . fmap (:[]) . Compose $ text

We are composing the ((->) s) and Scraper a functors.

The problem with this is that it trades newtype noise for nested fmap noise.

| improve this answer | |

Nested fmaps are very normal in haskell and extremely common, consider:

 myList = [Just 13, Just 7, Just 33, Nothing, Just 23]

exampleFunc :: [Maybe Int] -> [Maybe Int]
exampleFunc li = map (\el -> fmap (+1) el) li 

The prelude map function is a child of the fmap type, so this simple function is using nested fmap's.

| improve this answer | |

Not the answer you're looking for? Browse other questions tagged or ask your own question.