2011-09-17 13 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)なので、モナドは関与していませんが、モナドバインド演算子(>>=)と一緒に使用しています。また、タイプシグネチャを追加して、ランダムにしたい数字のタイプを指定する必要があります。

これに変更できます。

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

ただし、毎回新しいジェネレータを取得する必要はありません。我々はIOによって提供されるものを使用してこれを単純化することができます。

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

第2に、untilMのタイプシグネチャが間違っています。我々はそれを省略すると、コンパイラは、この場合にも

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

で正しいタイプを推測させることができ、あなたはreadLineを定義する必要はありません。それはすでにプレリュードに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 
+0

私は3つの変更を加えました。今は魅力のように機能します。 –

関連する問題