Когда вы делаете
definition :: ... tyvar ...
definition = ... (expr :: ... tyvar ...) ...
Два упоминания tyvar
не относятся к одному и тому же. Скорее, у нас есть правило, что все переменные типа во всех явных типах получают forall
ed:
definition :: forall tyvar. ... tyvar ...
definition = ... (expr :: forall tyvar. ... tyvar ...) ...
То есть переменные типа не имеют области видимости. Когда вы написали
thaw a :: ST s (STArray s (Int, Int) e) -- this is the "more correct" version of what you wrote
, вы на самом деле написали
thaw a :: forall e. ST s (STArray s (Int, Int) e)
Таким образом, вы сказали: «Возьмите Array
типа элемента e
и преобразуйте его в STArray
каждого элемента. тип". Это не работает.
Решение для Haskell 98 состоит в том, чтобы снова использовать вспомогательную функцию для связывания типа e
:
thawST :: Array i e -> ST s (STArray s i e)
thawST x = thaw x
det a = runST $ thawST a >> return 1
Конечно, thawST
- это просто thaw
с ограниченной подписью, так что это также работает (это решение несколько менее общее):
det a = runST $ (thaw :: Array i e -> ST s (STArray s i e)) a >> return 1
Если вы согласны с языковыми расширениями, вы можете использовать ExplicitForAll
и ScopedTypeVariables
:
det :: forall e. Num e => Array (Int, Int) e -> e -- e will be bound in the definition
det a = runST $ (thaw a :: ST s (STArray s (Int, Int) e)) >> return 1
-- s is not in scope, gets implicitly foralled
-- e is in scope, refers to that variable
Или вы можете использовать TypeApplications
вместо подписи
thaw :: (Ix i, IArray a e, MArray b e m) => a i e -> m (b i e)
-- so it takes type arguments in the order i(ndex) a(rray) e(lement) b(rray) m(onad)
det :: forall e. Num e => Array (Int, Int) e -> e
det a = runST $ thaw @_ @_ @_ @(STArray _) a >> return 1
-- _ means "infer this"
-- so we left the i, a, e, and m types to be inferred
-- and we specified that the result array was an STArray and left the state type inferred
-- the state type is currently unnamed: it's given to us by runST
-- but you need another type signature (runST (_ :: forall s. ST s <result>))
-- to actually reference it by name
-- therefore, we are forced to use _ and let it be inferred in the argument to thaw