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
失败
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'
我不明白为什么。任何人都可以解释一下吗?
答案 0 :(得分:10)
首先,您使用randomR
错误。它的类型是randomR :: RandomGen g => (a, a) -> g -> (a, g)
,因此没有涉及monad,但是你将它与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
。它已存在于Prelude中,名称为readLn
。
总而言之,我们得到了这个有效的代码。
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