在 Haskell 中,如何显式地给这个带有继承参数的特定集合函数签名?

In Haskell, how to explictly give a signature to this particular subfunction with inherited parameters?

假设你有这个功能

import Control.Monad
import Control.Monad.ST
import Data.STRef

f :: (Num a, Ord a) => STRef s a -> ST s ()
f i = loop
        where
            loop = do
                _i <- readSTRef i
                writeSTRef i (_i - 1)
                when (_i > 1) loop

loop的主体中,i被隐式定义为f的参数。 但是,我在给 loop 签名时遇到了问题。他告诉我它应该是 ST s (),所以我在 loop 的定义上面写了 loop :: ST s ()

但是 ghc 抱怨它无法将 loop 中的 sf 中的 s 相匹配。由于 loop 没有参数,它会在该循环的定义中创建自己的本地 forall s.,从而防止与 fs 匹配。

但令人惊讶的是它在没有显式签名的情况下编译。 PartialTypeSignature 有效,但它很丑陋并且不允许引用 s。如果我只是将 i 作为参数添加到 loop 但假设我很懒惰,它也会编译。

如何以编译的方式明确指定 loop 的签名?

难道不是所有使用隐式类型编译的东西都可以被赋予显式类型以便它仍然可以编译吗?

解决办法确实在于-XScopedTypeVariables

这个问题是因为如果你想引用一个已经存在的类型变量,这个变量必须明确量化。

{-# LANGUAGE ScopedTypeVariables #-}
import Control.Monad
import Control.Monad.ST
import Data.STRef

f :: forall s a. (Num a, Ord a) => STRef s a -> ST s ()
f i = loop
        where
            loop :: ST s ()
            loop = do
                _i <- readSTRef i
                writeSTRef i (_i - 1)
                when (_i > 1) loop