为什么调用以 IO () 作为返回值的函数会导致不明确的类型错误



我有两个函数,我的第一个函数调用第二个函数。第一个仅充当启动器。可悲的是,我收到以下错误。

runTo100 = rollDice 0 0 
rollDice :: (Ord t, Show a, Random t, Num a, Num t) => t -> a -> IO ()
rollDice amount n = do
gen <- newStdGen
if amount <= 100
    then do
        let rolled = dice gen
        rollDice (amount + rolled) (n + 1)
    else do
        putStrLn ("Rolls needed to reach 100: " ++ show n)

dice :: (Random a, RandomGen g, Num a) => g -> a
dice gen = head (take 1 $ randomRs (1, 6) gen)

错误:

Ambiguous type variable ‘t0’ arising from a use of ‘rollDice’
  prevents the constraint ‘(Ord t0)’ from being solved.
  Probable fix: use a type annotation to specify what ‘t0’ should be.
  These potential instances exist:
    instance (Ord a, Ord b) => Ord (Either a b)
      -- Defined in ‘Data.Either’
    instance Ord Ordering -- Defined in ‘GHC.Classes’
    instance Ord Integer
      -- Defined in ‘integer-gmp-1.0.2.0:GHC.Integer.Type’
    ...plus 23 others
    ...plus 89 instances involving out-of-scope types
    (use -fprint-potential-instances to see them all)
• In the expression: rollDice 0 0
  In an equation for ‘runTo100’: runTo100 = rollDice 0 0
|
119 | runTo100 = rollDice 0 0      |            ^^^^^^^^^^^^

为什么这会导致不明确的类型错误。我知道我必须在某处指定一个类型,但我是 haskell 的新手,我不完全了解发生了什么。我查看了各种帖子,但找不到任何对我有帮助的帖子。

提前感谢您的任何帮助。 :)

代码的问题在于 GHC 可以找到许多可用于t的类型。它必须是OrdRandomNum的实例。不幸的是,有很多类型符合要求。事实上,大多数Num实例也是RandomOrd(Complex可能是唯一的例外(。

在这一点上,GHC要么猜测,要么承认失败。让编译器猜测你的意思通常被认为是一件坏事,所以它会报告问题。

当你遇到这样的错误时,你需要在代码中的某个地方找到你想要使用的确切类型。通常,这应该尽可能位于调用堆栈的顶部,在这种情况下,这是rollDice的类型。

摆脱随机类型类约束,这似乎是多余的。

rollDice :: (Ord t, Show a, Num a, Num t) => t -> a -> IO ()

此外,您需要使用 randomR 函数并继续传回您通过应用该函数获得的新生成器,或者像您一样使用 randomRs 但检索一堆结果(要求 100 将保证有足够的滚动达到 100(,然后在您的总和超过 100 时丢弃其余的滚动。

您编写代码的方式,RNG 的滚动之间不保留任何状态,因此您一遍又一遍地获得相同的骰子滚动。也就是说,如果你第一次掷骰子,你得到4,那么你将继续得到数字4,直到你达到100的总和。

实际上,您的函数将有平等的机会打印值 16、20、25、33、50 和 100。你能证实这一点吗?

最新更新