[英]Two almost identical functions using STArray: why does one requires FlexibleContexts, and the other does not?
考虑 Haskell 函数
test :: ST s [Int]
test = do
arr <- newListArray (0,9) [0..9] :: ST s (STArray s Int Int)
let f i = do writeArray arr i (2*i)
readArray arr i
forM [1,2] f
和
test' :: ST s [Int]
test' = do
arr <- newListArray (0,9) [0..9] :: ST s (STArray s Int Int)
let f = \i -> do writeArray arr i (2*i)
readArray arr i
forM [1,2] f
第一个需要 FlexibleContexts 在 ghci 8.10.1 上编译,第二个编译没有额外的选项。 为什么?
特别欢迎根据类型变量s
的 scope 解释这种行为的答案。 作为后续,可以将什么(如果有)类型签名添加到 function f
以在没有 FlexibleContexts 的情况下进行test
编译? 最后,与单态限制有联系吗?
您可以在 GHCi 中检查 GHC 分配给f
的类型:
ghci> import Data.Array
ghci> import Data.Array.MArray
ghci> let arr :: STArray s Int Int; arr = undefined
ghci> :t \i -> do writeArray arr i (2*i); readArray arr i
\i -> do writeArray arr i (2*i); readArray arr i
:: (MArray (STArray s1) Int m, MArray (STArray s2) Int m) =>
Int -> m Int
这比您在评论中建议的类型以及需要FlexibleContexts
的原因更通用。
您可以添加您建议的类型签名( Int -> ST s Int
)以避免使用FlexibleContexts
:
{-# LANGUAGE ScopedTypeVariables #-}
...
test :: forall s. ST s [Int]
test = do
arr <- newListArray (0,9) [0..9] :: ST s (STArray s Int Int)
let
f :: Int -> ST s Int
f i = do
writeArray arr i (2*i)
readArray arr i
forM [1,2] f
请注意作用域类型变量和forall s.
这里是必需的,因为您需要确保所有类型签名中的s
都引用相同的类型变量,并且不要全部引入新的类型变量。
单态限制以不同方式对待您的第一个和第二个版本的原因是因为它不适用于看起来像函数的东西。 在您的第一个版本中, f
有一个参数,因此它看起来像 function ,因此将获得一个通用类型。 在您的第二个版本中, f
没有 arguments,因此它看起来不像 function,这意味着单态限制迫使它具有更具体的类型。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.