haskell - GHC 无法绑定多态函数而不对其进行单态化
问题描述
在原始代码中可以看到我只是将一个表达式提取到一个绑定中,这是 haskell 声称应该始终可能的基本内容之一。
最小案例(在 freenode 上 @dminuoso 的帮助下创建)
我想g
保持多态性(这样我就可以将它提供给其他期望它的函数):
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
main = do
let a :: forall t. Functor t => t () = undefined
let g :: forall u. Functor u => u () = a
pure ()
错误:
source_file.hs:6:44:
Couldn't match expected type ‘forall (u :: * -> *).
Functor u =>
u ()’
with actual type ‘t0 ()’
When checking that: t0 ()
is more polymorphic than: forall (u :: * -> *). Functor u => u ()
In the expression: a
#haskell IRC 上发布的原始问题(动机):
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
class Monad m => Monad' m where
instance Monad' IO where
f1 :: (forall m . Monad' m => m Int) -> IO Int
f1 g = do
let a :: forall n . Monad' n => n Int = g
a
-- this works
--f1 :: (forall m . Monad' m => m Int) -> IO Int
--f1 g = do
-- g
main = print $ "Hello, world!"
但我得到:
source_file.hs:12:45:
Couldn't match expected type ‘forall (n :: * -> *).
Monad' n =>
n Int’
with actual type ‘m0 Int’
When checking that: m0 Int
is more polymorphic than: forall (n :: * -> *). Monad' n => n Int
In the expression: g
基于https://ghc.haskell.org/trac/ghc/ticket/12587我尝试显式应用类型来帮助类型检查器:
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
class Monad m => Monad' m where
instance Monad' IO where
f1 :: (forall m . Monad' m => m Int) -> IO Int
f1 g = do
let a :: forall n . Monad' n => n Int = g @n
a
main = print $ "Hello, world!"
但后来我得到:
main.hs:13:48: error: Not in scope: type variable ‘n’
解决方案
关于模式类型签名的文档的相关位是:
与表达式和声明类型签名不同,模式类型签名不是隐式概括的。
因此,就像您所写的那样,模式签名是一种特殊情况,其中泛化(t
即将提到范围外类型变量的单a
态类型转换为多态类型的forall a. t
过程)没有完成。您可以使用任何其他形式的类型签名来恢复泛化过程;例如,而不是
let foo :: forall a. a = undefined
尝试:
let foo :: forall a. a
foo = undefined
推荐阅读
- python - 使用全局变量使用莫尔斯码列表对莫尔斯码进行编码和解码
- bash - 如何在 bash -c 命令中使用 sed
- python - 无法使用 pymupdf 搜索某些 pdf
- c++ - 我如何知道模板邻接列表中有哪些 Boost Graph 属性可用?
- sql - 在 shell 脚本中使用 sqlplus 格式化 csv 文件
- php - 如何同时使用 LIKE 和prepared statements?
- google-apps-script - 根据表单输入发送电子邮件
- javascript - 比较两个对象数组并获得差异
- flutter - 为什么我在使用 Flutter ChangeNotifierProvider 时出现内存问题?
- azure - 我的管道构建成功,但我需要在本地发生的 .xml 文件中发布结果,而不是在 DevOps 中