RankNTypes doesn't match return type

☆樱花仙子☆ 提交于 2019-12-06 07:50:36

While I'd prefer the solution @Oleg posted, I'd like to share an alternative.

Replace

main = print . g $ block [copy 10 1]

with

main = print (g (block [copy 10 1]))

Reason: impredicative types make it hard for the compiler to guess the type of (.) and ($) above.

Another option would be to annotate (.) and ($) with their instantiated type -- this would be rather cumbersome, though.

Using newtype for Block will keep s existential. Otherwise it will "leak" out


With original definition:

type Block = forall s . STVector s Int -> ST s Int
type Exp = Int -> Int -> Block

You could simplify failing example (main) to:

g . block

You'd like it's type to be:

g . block :: [Block] -> Int

But as the written out types of the components are:

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

Then when composed with (.), GHC keeps s general:

g . block :: forall s . [forall s0. STVector s0 Int -> ST s0 Int] -> Int

and tries to unify:

forall s1. STVector s1 Int -> ST s1 Int -- and
(STVector s Int -> ST s Int)

With newtype everything works perfectly (and no need for 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]
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!