Две почти одинаковые функции, использующие STArray: почему одна требует FlexibleContexts, а другая нет?

Рассмотрим функции 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будет особенно кстати. В качестве продолжения, какую (если есть) сигнатуру типа можно добавить в функцию f делать testкомпилировать без FlexibleContexts? Наконец, есть ли связь с ограничением мономорфизма?

1 ответ

Вы можете проверить, какой тип назначает GHC в GHCi:

      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

Это более общий тип, чем тот, который вы предлагаете в своих комментариях, и причина, по которой это необходимо.

Вы можете добавить подпись типа, которую вы предложили ( 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не имеет аргументов, поэтому она не похожа на функцию, а это означает, что ограничение мономорфизма заставляет ее иметь более конкретный тип.

Другие вопросы по тегам