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