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

Bil*_*l M 3 haskell typeclass newtype

假设我们有以下newtype定义:

newtype A = A { _run :: Monad m => A -> [Int] -> m Int }
Run Code Online (Sandbox Code Playgroud)

这不能用GHC 8.0.2编译:

error: Not in scope: type variable ‘m’
Run Code Online (Sandbox Code Playgroud)

正如我所料,用m类似的IO或类似的具体类类替换[].鉴于这没关系,为什么GHC不允许上面的签名?在此内部添加类型类约束有什么问题newtype

zbw*_*zbw 8

这取决于你想要存储的内容A.

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

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

myFunction :: Monad m => A m -> A m
Run Code Online (Sandbox Code Playgroud)

然后你可以在构造函数中使用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
Run Code Online (Sandbox Code Playgroud)

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

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

myFunction :: A -> A
Run Code Online (Sandbox Code Playgroud)

你不能在构造函数中使用A -> [Int] -> [Int]或者A -> [Int] -> Maybe Int在构造函数中使用forall它们,因为强制它们优先于任何 构造函数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
Run Code Online (Sandbox Code Playgroud)

如果您打算MonadA-value 使用不同的特定实例,这将非常有用.例如,镜头以这种方式工作,使用不同的仿函数来对镜头做不同的事情.


eph*_*ent 6

这个有可能:

{-# LANGUAGE RankNTypes #-}
newtype A = A { _run :: forall m. Monad m => A -> [Int] -> m Int }
Run Code Online (Sandbox Code Playgroud)

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

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

{-# LANGUAGE GADTs #-}
data A where A :: Monad m => (A -> [Int] -> m Int) -> A
Run Code Online (Sandbox Code Playgroud)

但也许你的意思更像

newtype A m = A { _run :: A m -> [Int] -> m Int }
Run Code Online (Sandbox Code Playgroud)

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

  • `data`和`newtype`版本之间存在巨大差异.它们完全是不同的意思.`data`版本创建了一个存在主义.无论何时应用构造函数,都会丢失类型`m`,并且永远无法恢复.`newtype`版本是通用的.构造函数所持有的值必须在具有`Monad`实例的所有`m`中是多态的.当你提取它时,你可以将它用于任何`m`. (2认同)