Can I make ImplicitParams work in this scenario?

I’m playing around with the following sample code

#!/usr/bin/env runhaskell
{-# LANGUAGE BlockArguments, ImplicitParams #-}
import System.Directory (listDirectory)
import Control.Monad (forM)
  
forEach m does = m >>= \list -> forM list (\it -> let ?it = it in does)
  
main = do
  forEach (listDirectory ".") do
    putStrLn ?it

With the following error message:

/tmp/poc.hs:10:14: error: [GHC-91416]
    • Unbound implicit parameter (?it::String)
        arising from a use of implicit parameter ‘?it’
    • In the first argument of ‘putStrLn’, namely ‘?it’
      In a stmt of a 'do' block: putStrLn ?it
      In the second argument of ‘forEach’, namely ‘do putStrLn ?it’
   |
10 |     putStrLn ?it
   |  

While I’m not sure why I can’t satisfy the compiler with this code , what would be my options, do I have to hand roll my own forM definition that captures the implicit parameter ?it in the type definition of the “callback” function?


Experimenting with less typing overall, I can live with an explicit callback parameter but would prefer not to.

You just need to give forEach a type signature:

forEach :: Monad m => m [a] -> ((?it :: a) => m b) -> m [b]

or more generally,

forEach :: (Monad m, Traversable t) => m (t a) -> ((?it :: a) => m b) -> m (t b)

GHC won’t infer a constraint in a function parameter for you; you have to write it explicitly.

4 Likes