在 Haskell 中,如何使用继承的参数显式地为这个特定的子函数签名?

J. *_* M. 1 haskell signature

说你有这个功能

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
Run Code Online (Sandbox Code Playgroud)

inloop的主体,i被隐式定义,因为它是来自 的参数f。但是我在给loop. Hie 告诉我它应该是ST s (),所以我写loop :: ST s ()了上面loop的定义。

但是 ghc 抱怨它无法将sfromloopsfrom匹配f。由于loop没有参数,它forall s.在该循环的定义中创建了自己的局部变量,以防止与f's匹配s

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

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

用隐式类型编译的所有东西都可以被赋予显式类型以便它仍然编译,这是不是真的?

sar*_*ara 5

解决方案确实在于 -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
Run Code Online (Sandbox Code Playgroud)