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).

1 Like

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.

2 Likes

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?