RankNTypes 与 return 类型不匹配
RankNTypes doesn't match return type
使用RankNTypes
,我定义了一个不依赖于类型变量的类型。这是解决下面案例的正确方法吗?
我需要在 ST s
中定义一些函数,当然,这些函数不依赖于 s
。然而,这会导致一个问题,即应用了两个 Int
的 Exp
表达式不会导致 Block
。为什么?
这里是复制者:
import Control.Monad.ST
import Data.Vector.Unboxed (Vector)
import qualified Data.Vector.Unboxed as U
import Data.Vector.Unboxed.Mutable (STVector)
import qualified Data.Vector.Unboxed.Mutable as UM
type Exp = Int -> Int -> Block
type Block = forall s . STVector s Int -> ST s Int
block :: [Block] -> Block
block [] _ = return 0 -- mapM doesn't work, either - ok, I kinda see why
block (e:es) a = do x <- e a
xs <- block es a
return $ x+xs
copy :: Exp
copy i j a = do
aj <- a `UM.unsafeRead` j
UM.unsafeWrite a i aj
return 1
f :: Block -> Vector Int -> Int
f blk ua = runST $ U.thaw ua >>= blk
g :: Block -> Int
g blk = f blk $ U.fromListN 12 [1..]
main = print . g $ block [copy 10 1]
我在最后一行得到分数的错误:
Couldn't match type `STVector s0 Int -> ST s0 Int'
with `forall s. STVector s Int -> ST s Int'
Expected type: Block
Actual type: STVector s0 Int -> ST s0 Int
In the return type of a call of `block'
Probable cause: `block' is applied to too few arguments
In the second argument of `($)', namely `block [copy 10 1]'
In the expression: print . g $ block [copy 10 1]
据我所知,预期类型和实际类型之间的差异是 forall s.
位。
将 newtype
用于 Block
将保持 s
存在。否则会"leak"出
原始定义:
type Block = forall s . STVector s Int -> ST s Int
type Exp = Int -> Int -> Block
您可以将失败示例 (main
) 简化为:
g . block
您希望它的类型是:
g . block :: [Block] -> Int
但是写出的组件类型是:
block :: forall s. [forall s0. STVector s0 Int -> ST s0 Int] -> (STVector s Int -> ST s Int)
g :: (forall s1. STVector s1 Int -> ST s1 Int) -> Int
然后当与 (.)
组合时,GHC 保持 s
一般:
g . block :: forall s . [forall s0. STVector s0 Int -> ST s0 Int] -> Int
并试图统一:
forall s1. STVector s1 Int -> ST s1 Int -- and
(STVector s Int -> ST s Int)
使用 newtype
一切正常(不需要 ImpredicativeTypes
):
{-# LANGUAGE RankNTypes #-}
import Control.Monad.ST
import Data.Vector.Unboxed (Vector)
import qualified Data.Vector.Unboxed as U
import Data.Vector.Unboxed.Mutable (STVector)
import qualified Data.Vector.Unboxed.Mutable as UM
type Exp = Int -> Int -> Block
newtype Block = Block { unBlock :: forall s . STVector s Int -> ST s Int }
block :: [Block] -> Block
block [] = Block $ \_ -> return 0 -- mapM doesn't work, either - ok, I kinda see why
block (e:es) = Block $ \a -> do x <- unBlock e a
xs <- unBlock (block es) a
return $ x + xs
copy :: Exp
copy i j = Block $ \a -> do
aj <- a `UM.unsafeRead` j
UM.unsafeWrite a i aj
return 1
f :: Block -> Vector Int -> Int
f (Block blk) ua = runST $ U.thaw ua >>= blk
g :: Block -> Int
g blk = f blk $ U.fromListN 12 [1..]
main = print . g $ block [copy 10 1]
虽然我更喜欢@Oleg 发布的解决方案,但我想分享一个替代方案。
替换
main = print . g $ block [copy 10 1]
和
main = print (g (block [copy 10 1]))
原因:指示类型使编译器很难猜测上面 (.)
和 ($)
的类型。
另一种选择是用实例化的类型注释 (.)
和 ($)
——不过这会很麻烦。
使用RankNTypes
,我定义了一个不依赖于类型变量的类型。这是解决下面案例的正确方法吗?
我需要在 ST s
中定义一些函数,当然,这些函数不依赖于 s
。然而,这会导致一个问题,即应用了两个 Int
的 Exp
表达式不会导致 Block
。为什么?
这里是复制者:
import Control.Monad.ST
import Data.Vector.Unboxed (Vector)
import qualified Data.Vector.Unboxed as U
import Data.Vector.Unboxed.Mutable (STVector)
import qualified Data.Vector.Unboxed.Mutable as UM
type Exp = Int -> Int -> Block
type Block = forall s . STVector s Int -> ST s Int
block :: [Block] -> Block
block [] _ = return 0 -- mapM doesn't work, either - ok, I kinda see why
block (e:es) a = do x <- e a
xs <- block es a
return $ x+xs
copy :: Exp
copy i j a = do
aj <- a `UM.unsafeRead` j
UM.unsafeWrite a i aj
return 1
f :: Block -> Vector Int -> Int
f blk ua = runST $ U.thaw ua >>= blk
g :: Block -> Int
g blk = f blk $ U.fromListN 12 [1..]
main = print . g $ block [copy 10 1]
我在最后一行得到分数的错误:
Couldn't match type `STVector s0 Int -> ST s0 Int'
with `forall s. STVector s Int -> ST s Int'
Expected type: Block
Actual type: STVector s0 Int -> ST s0 Int
In the return type of a call of `block'
Probable cause: `block' is applied to too few arguments
In the second argument of `($)', namely `block [copy 10 1]'
In the expression: print . g $ block [copy 10 1]
据我所知,预期类型和实际类型之间的差异是 forall s.
位。
将 newtype
用于 Block
将保持 s
存在。否则会"leak"出
原始定义:
type Block = forall s . STVector s Int -> ST s Int
type Exp = Int -> Int -> Block
您可以将失败示例 (main
) 简化为:
g . block
您希望它的类型是:
g . block :: [Block] -> Int
但是写出的组件类型是:
block :: forall s. [forall s0. STVector s0 Int -> ST s0 Int] -> (STVector s Int -> ST s Int)
g :: (forall s1. STVector s1 Int -> ST s1 Int) -> Int
然后当与 (.)
组合时,GHC 保持 s
一般:
g . block :: forall s . [forall s0. STVector s0 Int -> ST s0 Int] -> Int
并试图统一:
forall s1. STVector s1 Int -> ST s1 Int -- and
(STVector s Int -> ST s Int)
使用 newtype
一切正常(不需要 ImpredicativeTypes
):
{-# LANGUAGE RankNTypes #-}
import Control.Monad.ST
import Data.Vector.Unboxed (Vector)
import qualified Data.Vector.Unboxed as U
import Data.Vector.Unboxed.Mutable (STVector)
import qualified Data.Vector.Unboxed.Mutable as UM
type Exp = Int -> Int -> Block
newtype Block = Block { unBlock :: forall s . STVector s Int -> ST s Int }
block :: [Block] -> Block
block [] = Block $ \_ -> return 0 -- mapM doesn't work, either - ok, I kinda see why
block (e:es) = Block $ \a -> do x <- unBlock e a
xs <- unBlock (block es) a
return $ x + xs
copy :: Exp
copy i j = Block $ \a -> do
aj <- a `UM.unsafeRead` j
UM.unsafeWrite a i aj
return 1
f :: Block -> Vector Int -> Int
f (Block blk) ua = runST $ U.thaw ua >>= blk
g :: Block -> Int
g blk = f blk $ U.fromListN 12 [1..]
main = print . g $ block [copy 10 1]
虽然我更喜欢@Oleg 发布的解决方案,但我想分享一个替代方案。
替换
main = print . g $ block [copy 10 1]
和
main = print (g (block [copy 10 1]))
原因:指示类型使编译器很难猜测上面 (.)
和 ($)
的类型。
另一种选择是用实例化的类型注释 (.)
和 ($)
——不过这会很麻烦。