2011-09-17 51 views
1
guessOneToTen :: IO() 
guessOneToTen = 
    forever (do 
     number <- newNumber 
     guessed <- firstPrompt 
     untilM (== number) (const prompt) guessed 
     correct) 
    where 
     newNumber = newStdGen >>= randomR (1, 10) >>= return . fst 
     readLine = getLine >>= return . read 
     firstPrompt = putStr "Guess what number I am thinking of: " >> readLine 
     prompt = putStr "Sorry try again: " >> readLine 
     correct = putStrLn "You guessed correct!" 
     untilM :: (Monad m) => (a -> Bool) -> (a -> m a) -> a 
     untilM p f x 
      | p x = return() 
      | otherwise = f x >>= untilM p f 

这种失败为什么GHC在IO过程中遇到递归问题?

baby.hs:804:43: 
    Occurs check: cannot construct the infinite type: t0 = t0 -> IO a0 
    In the third argument of `untilM', namely `guessed' 
    In a stmt of a 'do' expression: 
     untilM (== number) (const prompt) guessed 
    In the first argument of `forever', namely 
     `(do { number <- newNumber; 
      guessed <- firstPrompt; 
      untilM (== number) (const prompt) guessed; 
      correct })' 

baby.hs:807:35: 
    Couldn't match expected type `IO a0' 
       with actual type `(a1, StdGen)' 
    Expected type: StdGen -> IO a0 
     Actual type: StdGen -> (a1, StdGen) 
    In the return type of a call of `randomR' 
    In the second argument of `(>>=)', namely `randomR (1, 10)' 

baby.hs:813:9: 
    Couldn't match type `a' with `a -> m()' 
     `a' is a rigid type variable bound by 
      the type signature for 
      untilM :: Monad m => (a -> Bool) -> (a -> m a) -> a 
      at baby.hs:813:9 
    The equation(s) for `untilM' have three arguments, 
    but its type `(a -> Bool) -> (a -> m a) -> a' has only two 
    In an equation for `guessOneToTen': 
     guessOneToTen 
      = forever 
       (do { number <- newNumber; 
        guessed <- firstPrompt; 
        untilM (== number) (const prompt) guessed; 
        correct }) 
      where 
       newNumber = newStdGen >>= randomR (1, 10) >>= return . fst 
       readLine = getLine >>= return . read 
       firstPrompt 
       = putStr "Guess what number I am thinking of: " >> readLine 
       prompt = putStr "Sorry try again: " >> readLine 
       .... 

baby.hs:815:42: 
    Couldn't match type `a' with `a -> m()' 
     `a' is a rigid type variable bound by 
      the type signature for 
      untilM :: Monad m => (a -> Bool) -> (a -> m a) -> a 
      at baby.hs:813:9 
    Expected type: (a -> m()) -> Bool 
     Actual type: a -> Bool 
    In the first argument of `untilM', namely `p' 
    In the second argument of `(>>=)', namely `untilM p f' 

baby.hs:815:44: 
    Couldn't match type `a' with `a -> m()' 
     `a' is a rigid type variable bound by 
      the type signature for 
      untilM :: Monad m => (a -> Bool) -> (a -> m a) -> a 
      at baby.hs:813:9 
    Expected type: (a -> m()) -> m (a -> m()) 
     Actual type: a -> m a 
    In the second argument of `untilM', namely `f' 
    In the second argument of `(>>=)', namely `untilM p f' 

baby.hs:815:44: 
    Couldn't match type `a' with `a -> m()' 
     `a' is a rigid type variable bound by 
      the type signature for 
      untilM :: Monad m => (a -> Bool) -> (a -> m a) -> a 
      at baby.hs:813:9 
    Expected type: (a -> m()) -> m (a -> m()) 
     Actual type: a -> m a 
    In the second argument of `untilM', namely `f' 
    In the second argument of `(>>=)', namely `untilM p f' 

我不明白为什么。任何人都可以点亮一下吗?

回答

10

首先,您正在使用randomR错误。它的类型是randomR :: RandomGen g => (a, a) -> g -> (a, g),所以没有monads参与,但是您将其与monadic绑定运算符(>>=)一起使用。你还必须添加一个类型签名来指定你想要的随机数。

我们可以将其更改为此。

newNumber = newStdGen >>= return . fst . randomR (1, 10) :: IO Int 

但是,每次都不需要新的发生器。我们可以通过使用由IO提供的那个来简化这个。

newNumber = randomRIO (1, 10) :: IO Int 

其次,您的untilM类型签名是错误的。我们可以直接忽略它,让编译器推断出正确的类型,在这种情况下是

untilM :: Monad m => (a -> Bool) -> (a -> m a) -> a -> m() 

而且,你不必定义readLine。它已经存在于名为readLn的Prelude中。

把这一切放在一起,我们得到这个工作代码。

guessOneToTen :: IO() 
guessOneToTen = 
    forever (do 
     number <- newNumber 
     guessed <- firstPrompt 
     untilM (== number) (const prompt) guessed 
     correct) 
    where 
     newNumber = randomRIO (1, 10) :: IO Int 
     firstPrompt = putStr "Guess what number I am thinking of: " >> readLn 
     prompt = putStr "Sorry try again: " >> readLn 
     correct = putStrLn "You guessed correct!" 
     untilM :: (Monad m) => (a -> Bool) -> (a -> m a) -> a -> m() 
     untilM p f x 
      | p x = return() 
      | otherwise = f x >>= untilM p f 
+0

我做了所有这三项修改。它现在像一个魅力。 –