No way to do ImplicitParams + Function definition syntax

Let’s say I have the following

doStuff :: (?assert :: Bool -> String -> IO ()) => IO () 

and I want to say, while I’m debugging a problem, that

main :: IO ()
main = doStuff where 
    ?assert x y = if x then pure () else putStrLn $ "Assertion failed <" ++ y ++ ">"

Will give a parse error. I get that this isn’t strictly necessary, but I’m wondering if there is a reason it wasn’t implemented and how hard it would be to fix (I. e. update GHC to make it work).

this reads like ?assert is being provided to doStuff via dynamic scoping? or am I not following the syntax?

implicitly read values from context are usually handled in Haskell via typeclasses.

Correct. This is called an “implicit parameter”.

The user’s guide actually mentions

An implicit-parameter binding group must be a collection of simple bindings to implicit-style variables (no function-style bindings, and no type signatures); these bindings are neither polymorphic or recursive.

I am just curious as to why. I couldn’t find the actual proposal.

You should open a GHC ticket about this. I couldn’t find one

It’s expected behavior, I’m just wondering why.

There’s an open issue #12360 about allowing implicit parameters in patterns. As far as I can see, the examples discussed there don’t actually cover the case of defining a function-valued implicit parameter, but a general solution would cover this case as well. The general consensus seems to be that there’s no technical reason not to allow this.

I was thinking about trying to fix the issue myself, as I want to contribute to GHC. However, while I think that HsLocalBindsLR and Pat are the things that need fixing, I’m worried that I’ll have to deal with tons of breakages, and I’m not being inspired by this thread:

I’m mainly self-taught in terms of Haskell, so I wouldn’t have much access to the wealth of knowledge that people have on GHC. Also, I haven’t even tried yet, the whole idea just seems so intimidating.

You can definitely say

main = doStuff where 
    ?assert = \ x y -> if x then pure () else putStrLn $ "Assertion failed <" ++ y ++ ">"

Your suggestion is to allow function-definition syntax in implicit-parameter bindings.

That might be possible (to a first approximation it’s just syntactic sugar) but there is always a cost/benefit tradeoff, one that you could explore with the community by writing a GHC proposal.

Things to consider: can the binding be recursive? Mutually recursive? Polymorphic? Can you put implicit parameter bindigns in patterns (?x, ?y) = blah?