I am trying to use the Beam Haskell library. Consider the following two snippets:
Version 1:
getDb = open "shoppingcart1.db"
runDebug conn = runBeamSqliteDebug putStr conn
runDebugInDb actions = do conn <- getDb
runDebug conn actions
Version 2:
dbFile = "shoppingcart1.db"
getDb = open dbFile
runDebug conn = runBeamSqliteDebug putStr conn
runDebugInDb actions = do conn <- getDb
runDebug conn actions
I would expect that the type inference would be the same. But the type inferred for runDebugInDb
is different, even when the inferred type for runDebug
and getDb
are the same.
ghci for version 1:
λ> :t (getDb, runDebug, runDebugInDb)
(getDb, runDebug, runDebugInDb)
:: (IO Connection, Connection -> SqliteM a -> IO a,
SqliteM b -> IO b)
ghci for version 2:
λ> :t (getDb, runDebug, runDebugInDb)
(getDb, runDebug, runDebugInDb)
:: (IO Connection, Connection -> SqliteM a -> IO a,
SqliteM () -> IO ())
The correct behavior is the first snippet, so that the query can return the result of the query. To get the second snippet to work, I have to explicitly annotate the type of runDebugInDb
.
Being new to Haskell, I don't understand well how the type inference system works. Why does the runDebugInDb
type get inferred differently in these two?
Update 1: A minimal example can be found here. This also shows the enabled extensions, which were from the Beam tutorial.
For some reason the behavior is a little bit different: the types from ghci are:
running version 1:
λ> :t (getDb, runDebug, runDebugInDb)
(getDb, runDebug, runDebugInDb)
:: (IO Connection, Connection -> SqliteM a -> IO a,
SqliteM b -> IO b)
running version 2:
λ> :t (getDb, runDebug, runDebugInDb)
(getDb, runDebug, runDebugInDb)
:: (IO Connection, Connection -> SqliteM a -> IO a,
SqliteM ghc-prim-0.6.1:GHC.Types.Any
-> IO ghc-prim-0.6.1:GHC.Types.Any)
Update 2: Turning off the ExtendedDefaultRules
extension allowed this to work. Enabling the MonomorphismRestriction
extension did not appear to change anything.
It seems that ExtendedDefaultRules
changes the interpretation of literals. If I understand correctly, the "shoppingcart1.db"
string literal is carried along to runDebug
and is interpreted differently in that function. Is this a correct interpretation, and how can I be sure about when this extension makes a difference?
Update 3: It seems that ExtendedDefaultRules
didn't actually change the behavior. It turns out the behavior is different if I load the entire file into ghci as opposed to copying the lines into ghci and running them one-by-one. The behavior is what I originally reported if I load the entire file (:l TypeInferenceExample.hs
) but the type inference is the same if the lines are copied into ghci.
(I thought I was unsetting the ExtendedDefaultRules
extension in ghci but actually wasn't.)