为什么以IO()作为返回值调用函数会导致模棱两可的类型错误?

时间:2019-04-24 12:49:48

标签: haskell

我有这两个功能,第一个功能叫第二个功能。第一个仅充当kickstarter。可悲的是我遇到了以下错误。

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还是陌生的,我还不完全了解发生了什么。我查看了各种帖子,但找不到任何可以帮助我的帖子。

在此先感谢您的帮助。 :)

2 个答案:

答案 0 :(得分:3)

您的代码存在的问题是,GHC可以找到许多可用于t的类型。它必须是OrdRandomNum的实例。不幸的是,有很多类型适合该法案。实际上,Num的大多数实例也是RandomOrdComplex可能是唯一的例外)。

这时,GHC必须猜测或承认失败。让编译器猜测您的意思通常被认为是一件坏事,因此它会报告问题。

当遇到这样的错误时,您需要在代码中找到某个地方来确定要使用的确切类型。通常,这应尽可能远地到达调用堆栈,在这种情况下,其类型为rollDice

答案 1 :(得分:2)

摆脱Random类型类约束,似乎是多余的。

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

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

您编写代码的方式是,在RNG滚动之间不会保持任何状态,因此您将一遍又一遍地获得相同的模具。 That is to say, if the first time you rolled the die, you got 4, then you will keep getting the number 4,直到总数达到100。

实际上,您的函数将有相等的机会打印值16、20、25、33、50和100。您可以确认吗?