以下是一些编译指示和一些导入:
{-# 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) }
werid的意思是,如果我给函数组合起了自己的名字,那么它就会再次检查类型:
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时的一些代码的简化版本,我正在试图理解为什么现在会发生这种情况。感谢您的帮助!
发布于 2011-12-01 23:36:37
正如你已经在你的文章标题中暗示的那样,这个问题与具有等级2的多态类型的runSTArray
有关。
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撰写的ICFP2008论文中解释了GHC如何实现不可预测的多态性:FPH : First-class Polymorphism for Haskell。底线是,虽然FPH通常会提供您所期望的行为,但有时在您的问题中描述的简单转换下不会保留可打印性:请参阅前述论文的6.2节。
发布于 2011-12-02 00:00:54
Stefan先我一步找到了答案--棘手的一点是,问题不是elems
和runSTArray
之间的$
和.
之间的竞争--而是runSTArray
之后的$
。由于something $ rankNthing
是如此常见,这里有一个聪明的小技巧(我忘记细节了),它试图让你把它当作一个绝佳的例子。但不知何故,使用早期的组合可以防止这一点。问题的位置由以下类型检查的事实来证明:
foo x = (elems . runSTArray) (
(newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int String)))
我不确定这本身就是一个bug,但它肯定是一个意想不到的行为,值得为它创建一个罚单,因为可能仍然有更好的算法来捕获像您提供的案例。
https://stackoverflow.com/questions/8343239
复制相似问题