2017-12-13 17 views
1

セクションの変数スコープを後でwhileM_にすることはできますか?例えばハスケル:whileM_可変範囲?

guess :: IO() 
guess = do 
    putStrLn "Please input your guess." 
    whileM_ 
    (do 
     guess <- getLine 
     return (guess /= "secret")) 
    (do 
     putStrLn ("You guessed: " ++ guess) 
     putStrLn ("And " ++ guess ++ " is wrong.")) 
    putStrLn "Right - Bye..." 

guessは、第doブロック内の範囲で使用するように利用不可能ではありません。

どのようにして範囲に入れることができますか?

ありがとうございます。

+2

'whileM_'は間違った機能です。あなたは簡単に再帰を使ってこれを手で書くことができますし、目的に合った関数を探すこともできます。 – dfeuer

答えて

4

whileM_には、これを実現する方法が組み込まれていません。そのコンビネータは実際には少し制限があります。 dfeuerが言っているように、あなたはたぶん再帰を使ってループを書くべきです。あなたはwhileM_のcondition-と実行部分の間の値を通信することができますしかし

guess :: IO() 
guess = do 
    putStrLn "Please input your guess." 
    whileJust_ 
    (do 
     lastGuess <- getLine -- don't use the name `guess` if that's already a global function name! 
     return $ if lastGuess /= "secret" 
       them Just lastGuess else Nothing) 
    (\lastGuess -> do 
     putStrLn $ "You guessed: " ++ lastGuess 
     putStrLn $ "And " ++ lastGuess ++ " is wrong.") 
    putStrLn "Right - Bye..." 

:または、実際には情報伝達のこの種のサポートを持っているループ構造を使用します。二つのオプション:IOで具体的に

  • 、あなたは常にIORefsを使用することができます。

    guess :: IO() 
    guess = do 
        putStrLn "Please input your guess." 
        bestGuess <- newIORef "" 
        whileM_ 
        (do lastGuess <- getLine 
         writeIORef bestGuess lastGuess 
         return $ lastGuess /= "secret") 
        (do lastGuess <- readIORef bestGuess 
         putStrLn $ "You guessed: " ++ lastGuess 
         putStrLn $ "And " ++ lasyGuess ++ " is wrong.") 
        putStrLn "Right - Bye..." 
    

    これはむしろIORefは基本的に変更可能な変数–ですが、時にはそれが賢明だハスケル–に避けています。間違いなく良いアイデアはここにあります。

  • IOの代わりに、純粋な機能状態変数を持つ専用のモナドを使用できます。それにはa monad transformerが必要です。やや高度な技術ですが、複雑なアプリケーションの場合は非常にうまくいくでしょう。

+0

この目的のために、厳密な 'StateT'は怠け者よりも妥当であると思われますが、私はその方向に何かが過剰なものだと思います。 – dfeuer

+0

私は 'whileJust_'を知らなかったし、それは仕事のための正しいツールのようだ。それを提案していただきありがとうございます。 – ericky