Lia*_*nne 4 polymorphism haskell
真的不知道这里发生了什么。我不是 Haskell 新手
\n我只是想调用我在两种不同类型上定义的多态函数,编译器会抱怨第二个函数调用,因为该类型与我第一次调用它时不同。
\nmain :: IO ()\nmain = do\n appData <- initializeAppData\n let log = getDebugPrint appData :: Show a => PrintLevel -> a -> IO ()\n log Log "My Game"\n log Debug appData\nRun Code Online (Sandbox Code Playgroud)\n我收到以下错误
\n/home/lianne/game/my-game/app/Main.hs:12:15: error:\n\xe2\x80\xa2 Couldn't match type \xe2\x80\x98AppData\xe2\x80\x99 with \xe2\x80\x98[Char]\xe2\x80\x99\n Expected: String\n Actual: AppData\n\xe2\x80\xa2 In the second argument of \xe2\x80\x98log\xe2\x80\x99, namely \xe2\x80\x98appData\xe2\x80\x99\n In a stmt of a 'do' block: log Debug appData\n In the expression:\n do appData <- initializeAppData\n let log = ...\n log Log "My Game"\n log Debug appData\nRun Code Online (Sandbox Code Playgroud)\n如果我切换最后两行,以便它记录appData之前的“我的游戏”,那么它会显示预期的 AppData,而实际类型是 String。
为了清楚起见,我添加了 let 上的类型定义,看看它是否会强制多态性。该getDebugPrint函数也有类型定义。
我正在使用堆栈和 ghc 8.8.1
\n是因为它是在 do 块中定义的吗?
\n这就是单态限制。
有关单态限制的更详细讨论,请参阅它的优秀标准问题:什么是单态限制?
但或多或少它说:如果定义的绑定没有任何语法参数(无论它的类型是否表明它有参数),并且绑定没有显式类型签名,那么任何具有类型类约束的类型变量都必须是解析为单一类型(满足约束)。
let log = getDebugPrint appData :: Show a => PrintLevel -> a -> IO ()
Run Code Online (Sandbox Code Playgroud)
let log = ...从语法上讲,是一个简单的变量绑定,没有为参数指定显式名称。所以这个条件适用。
但是“无显式类型签名”规则又如何呢?你在那里写了你想要的 type Show a => PrintLevel -> a -> IO (),那么什么给出呢?
您编写的方式实际上并未提供变量的类型签名log。相反,您为表达式提供类型注释getDebugPrint appData,这不是一回事。log可以给出作为右侧类型实例化的任何类型,它不必完全相同。1
因此,由于您没有给出变量本身的类型log,编译器必须推断出一个类型。这样做时,它将应用单态限制,这意味着它无法推断Show a => PrintLevel -> a -> IO (); 由于类型变量a受到限制,因此Show a必须将其实例化为特定的具体类型。它会查看您曾经 选择过的位置log,因此,如果您仅在单一类型上使用它,那么一切都会正常工作。但第一个调用log Log "My Game"要求它进行 pick String,第二个调用则要求它进行 pick AppData。显然它选择了String然后抱怨另一个呼叫不匹配;我不确定它是否总是根据第一次使用进行选择,或者是否是任意的,但这并不重要。
修复它的最简单方法是将您编写的类型放入类型签名中,log而不是表达式的类型注释中(无论如何,这确实是您有兴趣修复类型的原因),如下所示:
main :: IO ()
main = do
appData <- initializeAppData
let log :: Show a => PrintLevel -> a -> IO ()
log = getDebugPrint appData
log Log "My Game"
log Debug appData
Run Code Online (Sandbox Code Playgroud)
至于为什么你以前从未遇到过这个问题,从我上面的描述中你应该可以看出,造成这个问题的因素有以下几个:
NoMonomorphismRestriction扩展处于活动状态(从 GHC 8 左右开始,IIRC),这会禁用单态限制。因此,您在解释器中尝试的任何操作都不会出现此问题。因此,这很可能是该编码模式第一次同时触发所有条件。
1如果您认为这很愚蠢,请考虑以下内容:
x :: Int
x = 1
Run Code Online (Sandbox Code Playgroud)
如果您无法在右侧定义一个具有更通用表达式的特定类型变量(就像1type 一样) ,那么这将是无效的Num a => a。
| 归档时间: |
|
| 查看次数: |
220 次 |
| 最近记录: |