Skip to content

Instantly share code, notes, and snippets.

@EncodePanda
Last active September 7, 2020 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EncodePanda/aee425f86b8c3de9e8207c1e877632f3 to your computer and use it in GitHub Desktop.
Save EncodePanda/aee425f86b8c3de9e8207c1e877632f3 to your computer and use it in GitHub Desktop.
Functional Dependencies dilemma

hi all, I'm trying to get my head around functional dependencies I've created a simplified version of MonadReader that has no functional dependencies

class MyMonadReader r m where
  ask :: m r

What works as expected

When creating instances like

instance Monad m => MyMonadReader Bool (ReaderT r m) where
  ask = pure True
instance Monad m => MyMonadReader String (ReaderT r m) where
  ask = pure "string"

I see it compiling (as expected) and if I change MyMonadReader definition to use functional dependencies

class MyMonadReader r m | m -> r where
  ask :: m r

The code (as expected) does not compile.

    Functional dependencies conflict between instance declarations:
      instance Monad m => MyMonadReader Bool (ReaderT r m)
        -- Defined at src/Machinery/FunDep.hs:29:10
      instance Monad m => MyMonadReader String (ReaderT r m)
        -- Defined at src/Machinery/FunDep.hs:31:10

What does not work as expected

If my instances look following

instance Monad m => MyMonadReader r (ReaderT r m) where    -- <---------- THIS ONE WAS ADDED
  ask = ReaderT.ask 
instance Monad m => MyMonadReader Bool (ReaderT r m) where
  ask = pure True

I would expect the code also to not to compile. But it does. And I'm truly puzzled. Can anyone help with that puzzle? Why it does not complain, with a definition like class MyMonadReader r m | m -> r where there should be only one instance for ReaderT r m , right?

@EncodePanda
Copy link
Author

Encode Panda 1 hour ago
I was confused that it sometimes was able to report immediately but sometimes was waiting for the usage

Encode Panda 1 hour ago
thx for the answer

i-am-tom:kcsongor: 1 hour ago
Yeah, GHC tries its best, but its quick checks are nowhere near perfect. It's a pretty common misunderstanding with fundeps, I think - they don't impose restrictions on your instances, they impose restrictions on your usages. GHC's just often clever enough to do both

Encode Panda < 1 minute ago
👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment