有没有办法在编写类型签名的同时指定隐式参数的递归行为?

Is there a way to specify the recursive behaviour of implicit parameters while still writing a type signature?

根据 GHC 用户指南,只有当函数具有类型签名时,显式绑定的隐式参数才会传播到递归调用中,否则,将使用原始调用中的隐式参数。

fu True = ?gn
fu False = let ?gn = not ?gn in fu True
br :: (?sp :: Bool) => Bool -> Bool
br True = ?sp
br False = let ?sp = not ?sp in br True
ghci> let ?gn = True in fu False
True
ghci> let ?sp = True in br False
False

但是,如果我想为 fu 提供类型签名,同时保留其行为怎么办?我可以这样做吗?

您可以进行“worker-wrapper”转换:获取函数的递归部分并将其移动到本地绑定中。这使您可以使隐式参数显式化,因此递归调用没有歧义。

fu :: (?gn :: Bool) => Bool -> Bool
fu = go ?gn
    where
        go gn True = gn
        go gn False = go (not gn) True

我个人觉得这个版本更容易理解。