0
\$\begingroup\$

Given:

*Main> :t text
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.

\$\endgroup\$

closed as too broad by t3chb0t, Ethan Bierlein, mdfst13, Hosch250, Mathias Ettinger Jan 10 '17 at 10:06

Please edit the question to limit it to a specific problem with enough detail to identify an adequate answer. Avoid asking multiple distinct questions at once. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • \$\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
3
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$

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