为什么这个等效的程序不能编译?

Mai*_*tor 8 haskell impredicativetypes

这个程序:

{-# LANGUAGE RankNTypes, ImpredicativeTypes #-}

import qualified Data.Vector.Mutable as MV
import qualified Data.Vector as V
import Control.Monad.ST
import Control.Monad.Primitive

unsafeModify :: [(forall s . MV.MVector s Int -> ST s ())] -> V.Vector Int -> V.Vector Int
unsafeModify mods vec = runST $ do
    mvec <- V.unsafeThaw vec
    (mods !! 0) mvec
    V.unsafeFreeze mvec
Run Code Online (Sandbox Code Playgroud)

编译.这个程序:

{-# LANGUAGE RankNTypes, ImpredicativeTypes #-}

import qualified Data.Vector.Mutable as MV
import qualified Data.Vector as V
import Control.Monad.ST
import Control.Monad.Primitive

unsafeModify :: [(forall s . MV.MVector s Int -> ST s ())] -> V.Vector Int -> V.Vector Int
unsafeModify mods vec = runST $ do
    mvec <- V.unsafeThaw vec
    ($ mvec) (mods !! 0)
    V.unsafeFreeze mvec
Run Code Online (Sandbox Code Playgroud)

不编译时出现以下错误:

Muts.hs:10:15:
    Couldn't match type ‘forall s1. UV.MVector s1 Int -> ST s1 ()’
                  with ‘UV.MVector s Int -> ST s a0’
    Expected type: [UV.MVector s Int -> ST s a0]
      Actual type: [forall s. UV.MVector s Int -> ST s ()]
    Relevant bindings include
      mvec :: UV.MVector s Int (bound at Muts.hs:9:5)
    In the first argument of ‘(!!)’, namely ‘mods’
    In the first argument of ‘$ mvec’, namely ‘(mods !! 0)’
Run Code Online (Sandbox Code Playgroud)

为什么?

Zet*_*eta 3

注意:这篇文章是用哈斯克尔语言写的。您可以将其另存为 Unsafe.lhs 并在 GHCi 中尝试。


让我们比较一下不同线路的类型:

 mods                ::     [(forall s . MV.MVector s Int -> ST s ())]
(mods !! 0)          ::      (forall s . MV.MVector s Int -> ST s ())
(mods !! 0)  mvec    ::       forall s. ST s ()


($ mvec)             ::     (MV.Vector s Int -> b) -> b
         (mods !! 0) ::     (forall s . MV.MVector s Int -> ST s ())
($ mvec) (mods !! 0) ::     ????????????????????????
Run Code Online (Sandbox Code Playgroud)

$由于的类型,它们并不等效:

($) :: forall a b. (a -> b) -> a -> b
Run Code Online (Sandbox Code Playgroud)

而你需要一些东西

($)  :: (a ~ (forall s . MV.MVector s Int -> ST s ())) =>
      (a -> b) -> a -> b
Run Code Online (Sandbox Code Playgroud)

这是不合法的。

但是,让我们看看您真正想要做什么。

> {-# LANGUAGE RankNTypes #-}

> import qualified Data.Vector.Mutable as MV
> import qualified Data.Vector as V
> import Control.Monad.ST
> import Control.Monad.Primitive

  unsafeModify :: ??? -> V.Vector Int -> V.Vector Int

> unsafeModify mods vec = runST $ do
>   mvec <- V.unsafeThaw vec
>   mapM_ ($ mvec) (mods !! 0)
>   V.unsafeFreeze mvec
Run Code Online (Sandbox Code Playgroud)

由于unsafeModify第一个参数的多态性,事情变得混乱mods。你原来的类型

[(forall s . MV.MVector s Int -> ST s ())]
Run Code Online (Sandbox Code Playgroud)

告诉我们它是一个函数列表,其中每个函数的参数都是多态的s,因此每个函数都可以使用另一个s函数。然而,这太过分了。s如果在整个列表中共享就可以了:

(forall s. [MV.MVector s Int -> ST s ()])
Run Code Online (Sandbox Code Playgroud)

毕竟,我们希望在同一ST计算中使用所有函数,因此流状态令牌的类型s可以相同。我们最终得到

> unsafeModify :: (forall s. [MV.MVector s Int -> ST s ()]) -> V.Vector Int -> V.Vector Int
Run Code Online (Sandbox Code Playgroud)

现在,无论您是否使用($ mvec) (mods !! 0)(mods !! 0) mvecmapM_,您的代码都可以愉快地编译,因为现在已通过整个列表s正确修复。runST