可以在newtype定义中使用类型类约束吗?

时间:2017-04-17 02:00:10

标签: haskell typeclass newtype

假设我们有以下newtype定义:

newtype A = A { _run :: Monad m => A -> [Int] -> m Int }

这不能用GHC 8.0.2编译:

error: Not in scope: type variable ‘m’

使用像mIO这样的具体类型类替换[]确实可以编译,正如我所期望的那样。鉴于这没关系,为什么GHC不允许上面的签名?在newtype内添加类型类约束有什么问题?

3 个答案:

答案 0 :(得分:8)

这取决于您在A中尝试存储的内容。

如果您尝试存储此类任何功能,只要mMonad,请将其用作类型参数,并在您的函数中指定此约束:

newtype A m = A { _run :: A m -> [Int] -> m Int }

myFunction :: Monad m => A m -> A m

然后,您可以在构造函数中包含A [] -> [Int] -> [Int]A Maybe -> [Int] -> Maybe Int等内容。

f :: A Maybe -> [Int] -> Maybe Int
f _ (x:_) = Just x
f _ [] = Nothing

g :: Monad m => A m -> [Int] -> m Int
g _ xs = return $ head xs

myA :: A Maybe
myA = A f  -- this works

myOtherA :: Monad m => A m
myOtherA = A g  -- this works too

另一方面,如果要强制存储的数据是多态的,可以使用GHC扩展RankNTypes

{-# LANGUAGE RankNTypes #-}
newtype A = A { _run :: forall m. Monad m => A -> [Int] -> m Int }

myFunction :: A -> A

你在构造函数中不能拥有A -> [Int] -> [Int]A -> [Int] -> Maybe Int之类的内容,因为forall强制它们优先于任何 {{ 1}},所以它必须是Monad m类型。

Monad m => A -> [Int] -> Maybe Int

如果您打算为f :: A -> [Int] -> Maybe Int f _ (x:_) = Just x f _ [] = Nothing g :: Monad m => A -> [Int] -> m Int g _ xs = return $ head xs myA :: A myA = A f -- this does not work ; it wants forall m. Monad m => m, not [] myOtherA :: A myOtherA = A g -- this does work - 值使用不同的特定Monad实例,这只会非常有用。例如,镜头通过使用不同的仿函数来对镜头做不同的事情。

答案 1 :(得分:5)

这是可能的:

{-# LANGUAGE RankNTypes #-}
newtype A = A { _run :: forall m. Monad m => A -> [Int] -> m Int }

很难说出你想做什么,但这并不是很有用。类型A的任何值都需要适用于所有monad(您无法选择)。

这也是可能的,具有相同的限制:

{-# LANGUAGE GADTs #-}
data A where A :: Monad m => (A -> [Int] -> m Int) -> A

但也许你的意思更像是

newtype A m = A { _run :: A m -> [Int] -> m Int }

这允许使用不同monad的不同类型A的值。

答案 2 :(得分:-1)

在创建Monad类型的数据时,GHC如何知道要使用的A实例?

或者换句话说,类型变量m不在类型定义左侧的范围内。这意味着它不知道m应该是什么,并且不能解决它。这是隐含的。

我确信你可以用扩展程序做一些你想做的事情,可能使用明确的forall。 (RankNTypes扩展名),但是我们需要知道你的内容。