存在类型的类型变量介绍

问题描述

haskell 中是否有任何绑定器来引入在类型中量化的类型变量(和约束)?

我可以添加一个额外的参数,但它违背了目的。

{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE GADTs #-}


data Exists x = forall m. Monad m => Exists (m x)

convBad ::  x -> Exists x  
convBad  x = Exists @m (return @m x,undefined) --Not in scope: type variable ‘m’typecheck


data Proxy (m:: * -> *) where Proxy :: Proxy m

convOk ::  Monad m => x -> Proxy m -> Exists x 
convOk  x (_ :: Proxy m) = Exists (return @m x)

解决方法

要将类型变量带入作用域,请使用 forall(由 ExplicitForall 启用,由 ScopedTypeVariables 隐含):

convWorksNow :: forall m x. Monad m => x -> Exists x  
convWorksNow x = Exists (return @m x)

-- Usage:
ex :: Exists Int
ex = convWorksNow @Maybe 42

但是,无论您是这样做还是通过 Proxy,请记住,必须在创建 m选择 Exists。因此,调用 Exists 构造函数的人必须知道 m 是什么。

如果您希望它是相反的 - 即无论谁解开一个 Exists 值都选择了 m,那么您的 forall 应该在内部:

newtype Exists x = Exists (forall m. Monad m => m x)

convInside :: x -> Exists x
convInside x = Exists (return x)

-- Usage:
ex :: Exists Int
ex = convInside 42

main = do
  case ex of
    Exists mx -> mx >>= print  -- Here I choose m ~ IO

  case ex of
    Exists mx -> print (fromMaybe 0 mx)  -- Here I choose m ~ Maybe

此外,正如@dfeuer 在评论中指出的那样,请注意您的原始类型定义(外部带有 forall 的类型)除了表示 x 的类型(相同正如Proxy 所做的那样)。这是因为任何使用这种值的人都必须能够使用任何 monad m,并且您可以使用 monad 做任何事情,除非您知道它是什么。你不能把它绑定在 IO 内,因为它不一定是 IO,你不能用 JustNothing 模式匹配它,因为它不一定是 {{1} }, 等等。你唯一能做的就是用 Maybe 绑定它,但是你会得到它的另一个实例,然后你又回到了原点。