以下是一些pragma和一些导入:
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Monad.ST
import Data.Array.ST
import Data.Array
现在这是我的问题。以下代码类型检查:
foo :: forall a. a -> [a]
foo x = elems $ runSTArray $ do
newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int a)
然而,当我用作文替换$
时:
foo :: forall a. a -> [a]
foo x = elems . runSTArray $ do
newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int a)
我收到此错误:
Couldn't match expected type `forall s. ST s (STArray s i0 e0)'
with actual type `ST s0 (STArray s0 Int a)'
In the expression:
newListArray (1, 10) (replicate 10 x) :: ST s (STArray s Int a)
In the second argument of `($)', namely
`do { newListArray (1, 10) (replicate 10 x) ::
ST s (STArray s Int a) }'
In the expression:
elems . runSTArray
$ do { newListArray (1, 10) (replicate 10 x) ::
ST s (STArray s Int a) }
有什么问题,如果我给函数组合赋予自己的名字,那么它再次进行类型检查:
elemSTArray = elems . runSTArray
foo :: forall a. a -> [a]
foo x = elemSTArray $ do
newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int a)
我不确定这里发生了什么。我希望第二段代码可以很好地进行类型检查。如果我给这个组合函数赋予它自己的名字,我不明白为什么再次强调它。
这是我从GHC 6.2升级到7时遇到的一些代码的简化版本,我试图理解为什么会发生这种情况。谢谢你的帮助!
答案 0 :(得分:15)
正如您在帖子标题中暗示的那样,问题与runSTArray
的多态类型为2级有关。
runSTArray :: Ix i => (forall s. ST s (STArray s i e)) -> Array i e
使用
elems :: Ix i => Array i e -> [e]
和
($) :: (a -> b) -> a -> b
编写runSTArray $ ...
意味着a
的类型模式中的类型变量($)
需要使用多态类型而不是单态类型进行实例化。这需要所谓的不可预测的多态性。在Dimitrios Vytiniotis,Stephanie Weirich和Simon Peyton Jones的ICFP 2008论文中解释了GHC如何实现预测性多态性:FPH : First-class Polymorphism for Haskell。最重要的是,虽然FPH通常会为您提供您期望的行为,但有时候在您的问题中描述的简单转换中不会保留可键性:请参阅上述文章的第6.2节。
答案 1 :(得分:9)
Stefan打败了我的答案 - 棘手的一点是$
与.
elems
之间runSTArray
和$
之间的问题 - 这是{ {1}}关注runSTArray
。由于something $ rankNthing
是如此常见,因此有一个聪明的位(我忘记了细节)试图让你做到这一点作为一个角落案例。但不知何故使用早期的组合可以防止这种情况发生问题的位置通过以下事实证明:
foo x = (elems . runSTArray) (
(newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int String)))
我不确定这本身就是一个错误,但它确实是一个值得创建故障单的意外行为,因为可能仍然有更好的算法来捕获像你提供的那样的情况。