簡體   English   中英

使用 STArray 的兩個幾乎相同的函數:為什么一個需要 FlexibleContexts,而另一個不需要?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM