Skip to content

Instantly share code, notes, and snippets.

@Tehnix
Created November 17, 2018 23:49
Show Gist options
  • Save Tehnix/7a70f9c0cf7c5fbf02217218cddac064 to your computer and use it in GitHub Desktop.
Save Tehnix/7a70f9c0cf7c5fbf02217218cddac064 to your computer and use it in GitHub Desktop.
Problems with type inference, `HasAwsCredentials env String` and `Member (Reader env) effs`
#!/usr/bin/env stack
-- stack --resolver lts-12.16 script --package freer-simple --package lens
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
module Test where
import Control.Lens (makeLensesWith, camelCaseFields)
import Control.Lens ((^.))
import Control.Monad.Freer (Eff, Member, LastMember)
import qualified Control.Monad.Freer as Freer
import Control.Monad.Freer.Reader (Reader)
import qualified Control.Monad.Freer.Reader as Reader
data Config = Config
{ configAwsCredentials :: String
, configOrganization :: String
} deriving (Show)
makeLensesWith camelCaseFields ''Config
test :: (HasAwsCredentials env String, Member (Reader env) effs, LastMember IO effs) => Eff effs String
test = do
config <- Reader.ask
pure $ config ^. awsCredentials
main :: IO ()
main = do
let
config = Config
{ configAwsCredentials = "Test Creds"
, configOrganization = "Codetalk"
}
creds <- Freer.runM . Reader.runReader config $ test
putStrLn creds
{-
λ ~/Desktop ./UsingHasConfig.hs
/Users/tehnix/Desktop/UsingHasConfig.hs:27:13: error:
• Overlapping instances for Member (Reader s0) effs
arising from a use of ‘Reader.ask’
Matching givens (or their superclasses):
Member (Reader env) effs
bound by the type signature for:
test :: forall env (effs :: [* -> *]).
(HasAwsCredentials env String, Member (Reader env) effs,
LastMember IO effs) =>
Eff effs String
at /Users/tehnix/Desktop/UsingHasConfig.hs:25:1-103
Matching instances:
instance (Data.OpenUnion.Internal.FindElem t r,
Data.OpenUnion.Internal.IfNotFound t r r) =>
Member t r
-- Defined in ‘Data.OpenUnion.Internal’
(The choice depends on the instantiation of ‘s0, effs’)
• In a stmt of a 'do' block: config <- Reader.ask
In the expression:
do config <- Reader.ask
pure $ config ^. awsCredentials
In an equation for ‘test’:
test
= do config <- Reader.ask
pure $ config ^. awsCredentials
|
27 | config <- Reader.ask
| ^^^^^^^^^^
/Users/tehnix/Desktop/UsingHasConfig.hs:28:20: error:
• Could not deduce (HasAwsCredentials s0 String)
arising from a use of ‘awsCredentials’
from the context: (HasAwsCredentials env String,
Member (Reader env) effs, LastMember IO effs)
bound by the type signature for:
test :: forall env (effs :: [* -> *]).
(HasAwsCredentials env String, Member (Reader env) effs,
LastMember IO effs) =>
Eff effs String
at /Users/tehnix/Desktop/UsingHasConfig.hs:25:1-103
The type variable ‘s0’ is ambiguous
Relevant bindings include
config :: s0
(bound at /Users/tehnix/Desktop/UsingHasConfig.hs:27:3)
These potential instance exist:
instance HasAwsCredentials Config String
-- Defined at /Users/tehnix/Desktop/UsingHasConfig.hs:23:1
• In the second argument of ‘(^.)’, namely ‘awsCredentials’
In the second argument of ‘($)’, namely ‘config ^. awsCredentials’
In a stmt of a 'do' block: pure $ config ^. awsCredentials
|
28 | pure $ config ^. awsCredentials
| ^^^^^^^^^^^^^^
/Users/tehnix/Desktop/UsingHasConfig.hs:37:51: error:
• Ambiguous type variable ‘env0’ arising from a use of ‘test’
prevents the constraint ‘(HasAwsCredentials
env0 String)’ from being solved.
Probable fix: use a type annotation to specify what ‘env0’ should be.
These potential instance exist:
instance HasAwsCredentials Config String
-- Defined at /Users/tehnix/Desktop/UsingHasConfig.hs:23:1
• In the second argument of ‘($)’, namely ‘test’
In a stmt of a 'do' block:
creds <- Freer.runM . Reader.runReader config $ test
In the expression:
do let config = ...
creds <- Freer.runM . Reader.runReader config $ test
putStrLn creds
|
37 | creds <- Freer.runM . Reader.runReader config $ test
| ^^^^
-}
@Tehnix
Copy link
Author

Tehnix commented Nov 18, 2018

For posterity's sake, I'll include the fix here: We needed to enable three more language extensions,

...
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE TypeApplications #-}
...

And test becomes,

test :: forall env effs. (HasAwsCredentials env String, Member (Reader env) effs, LastMember IO effs) => Eff effs String
test = do
  config <- Reader.ask @env
  pure $ config ^. awsCredentials

where you can notice the explicit forall and the Reader.ask @env type application. Finally we also added type annotations in main, with creds <- Freer.runM . Reader.runReader config $ test @Config.

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