所以我在 Haskell 中有一个函数,为了问这个问题,我已经简化了它:
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
我希望将myFn
' 的依赖项helper
放入 aReader
中,因为控制反转允许我在测试中切换实现:
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
这很好用,除了我特别不喜欢这三行:
myFn' <- myFn (a - 1)
helper'' <- asks helper'
return (foldMap helper'' myFn')
我觉得应该有一种方法来提升foldMap
,就像通过它的组合mapM
的提升版本一样。理想情况下,我希望将这三行合并为一行:map
sequence
foldMapM helper'' (partitions (n - 1))
假如说:helper'' :: Int -> MyReader (Set Int)
这当然需要具有foldMapM
类似于以下签名的函数:
foldMapM
:: (Monad m, Foldable t, Monoid n)
=> (a -> m n)
-> m (t a)
-> m n
我已经尝试了很多东西,但我似乎无法实现这个功能!任何人都可以帮忙吗?