首页 > 解决方案 > 加载文件与将行粘贴到 GHCI 时类型推断不同

问题描述

我正在尝试使用Beam Haskell库。考虑以下两个片段:

版本 1:

getDb                = open "shoppingcart1.db"
runDebug conn        = runBeamSqliteDebug putStr conn
runDebugInDb actions = do conn <- getDb
                          runDebug conn actions

版本 2:

dbFile               = "shoppingcart1.db"
getDb                = open dbFile
runDebug conn        = runBeamSqliteDebug putStr conn
runDebugInDb actions = do conn <- getDb
                          runDebug conn actions

我希望类型推断是相同的。但是推断的类型runDebugInDb是不同的,即使推断的类型runDebuggetDb是相同的。

版本 1 的 ghci:

λ> :t (getDb, runDebug, runDebugInDb)
(getDb, runDebug, runDebugInDb)
  :: (IO Connection, Connection -> SqliteM a -> IO a,
      SqliteM b -> IO b)

版本 2 的 ghci:

λ> :t (getDb, runDebug, runDebugInDb)
(getDb, runDebug, runDebugInDb)
  :: (IO Connection, Connection -> SqliteM a -> IO a,
      SqliteM () -> IO ())

正确的行为是第一个片段,以便查询可以返回查询的结果。为了让第二个片段工作,我必须明确注释runDebugInDb.

作为 Haskell 的新手,我不太了解类型推断系统的工作原理。为什么runDebugInDb在这两者中推断类型不同?


更新 1:可以在此处找到一个最小示例。这也显示了已启用的扩展,它们来自 Beam 教程。

由于某种原因,行为有点不同:来自 ghci 的类型是:

运行版本 1:

λ> :t (getDb, runDebug, runDebugInDb)
(getDb, runDebug, runDebugInDb)
  :: (IO Connection, Connection -> SqliteM a -> IO a,
      SqliteM b -> IO b)

运行版本 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)

更新 2:关闭ExtendedDefaultRules扩展允许它工作。启用MonomorphismRestriction扩展似乎没有改变任何东西。

似乎ExtendedDefaultRules改变了文字的解释。如果我理解正确,"shoppingcart1.db"字符串文字会被带到runDebug该函数中并在该函数中进行不同的解释。这是一个正确的解释吗?我如何确定这个扩展何时会产生影响?


更新 3:似乎ExtendedDefaultRules实际上并没有改变行为。事实证明,如果我将整个文件加载到 ghci 中,而不是将行复制到 ghci 中并一个接一个地运行它们,那么行为会有所不同。如果我加载整个文件 (),则行为是我最初报告的,:l TypeInferenceExample.hs但如果将行复制到 ghci 中,类型推断是相同的。

(我以为我ExtendedDefaultRules在 ghci 中取消了扩展,但实际上并没有。)

标签: haskelltype-inference

解决方案


推荐阅读