首页 > 解决方案 > 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’

标签: haskellrank-n-types

解决方案


关于模式类型签名的文档的相关位是:

与表达式和声明类型签名不同,模式类型签名不是隐式概括的。

因此,就像您所写的那样,模式签名是一种特殊情况,其中泛化(t即将提到范围外类型变量的单a态类型转换为多态类型的forall a. t过程)没有完成。您可以使用任何其他形式的类型签名来恢复泛化过程;例如,而不是

let foo :: forall a. a = undefined

尝试:

let foo :: forall a. a
    foo = undefined

推荐阅读