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?
这取决于你想要存储的内容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)
如果您打算Monad为A-value 使用不同的特定实例,这将非常有用.例如,镜头以这种方式工作,使用不同的仿函数来对镜头做不同的事情.
这个有可能:
{-# 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 的不同类型的值.