So I have a function in Haskell that I've simplified for the purpose of asking this question:
import Data.Foldable
import Data.Set
myFn :: Int -> Set Int
myFn a
| a <= 0 = singleton 1
| otherwise = foldMap helper (myFn (a - 1))
helper :: Int -> Set Int
helper a = insert (a + 2) (singleton a)
main :: IO ()
main = print . Data.Set.toList $ myFn 5
I want to have myFn
's dependency on helper
to be put into a Reader
, since inversion of control allows me to switch implementations in my tests:
import Control.Monad.Reader
import Data.Foldable
import Data.Set
data MyEnv = MyEnv { helper' :: Int -> Set Int }
type MyReader = Reader MyEnv
myFn :: Int -> MyReader (Set Int)
myFn a
| a <= 0 = return $ singleton 1
| otherwise = do
myFn' <- myFn (a - 1)
helper'' <- asks helper'
return (foldMap helper'' myFn')
helper :: Int -> Set Int
helper a = insert (a + 2) (singleton a)
main :: IO ()
main =
let
myEnv = MyEnv helper
in
print . Data.Set.toList $ runReader (myFn 5) myEnv
This works fine, except I don't like these three lines in particular:
myFn' <- myFn (a - 1)
helper'' <- asks helper'
return (foldMap helper'' myFn')
I feel like there should be a way to lift foldMap
in the same way as mapM
is a lifted version of map
through its composition with sequence
. Ideally, I would like those three lines to collapse down to one:
foldMapM helper'' (partitions (n - 1))
Assuming that: helper'' :: Int -> MyReader (Set Int)
This would of course require a foldMapM
function with a signature similar to:
foldMapM
:: (Monad m, Foldable t, Monoid n)
=> (a -> m n)
-> m (t a)
-> m n
I have tried so many things, but I just cannot seem to implement this function, though! Can anyone help?