質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Haskell

Haskellは高い機能性をもった関数型プログラミング言語で、他の手続き型プログラミング言語では難しいとされている関数でも容易に行うことができます。強い静的型付け、遅延評価などに対応しています。

Q&A

解決済

1回答

1099閲覧

Haskellでプロンプトを表示させつつ標準入力を行いたい

AGadget

総合スコア60

Haskell

Haskellは高い機能性をもった関数型プログラミング言語で、他の手続き型プログラミング言語では難しいとされている関数でも容易に行うことができます。強い静的型付け、遅延評価などに対応しています。

1グッド

0クリップ

投稿2020/05/19 16:06

Haskellでプロンプトを表示しつつ標準入力を受け付ける方法を探しています。

質問の背景

「すごいHaskellたのしく学ぼう!」という書籍を参考に、Haskellを勉強しています。

関数の定義や四則演算といった部分がなんとか理解できましたので、標準入出力――IOモナドの分野に着手し始めています。

色々調べてputStrやprintを使って標準出力すること。また、getLineやreadLnを用いて標準入力を受け付けることはできるようになりました。

ただ、そこから一歩進んで、プロンプトを表示させつつ標準入力を受け付けるプログラムを組もうとしたところで躓いています。

本題

作りたいプログラムは以下のようなものです。

C

1#include <stdio.h> 2#include <stdbool.h> 3 4int main(void) { 5 printf("処理開始\n"); 6 while (true) { 7 printf("[1] グー [2] チョキ [3] パー : "); 8 int input = 0; 9 scanf("%d", &input); 10 switch (input) { 11 case 1: 12 printf("グー"); 13 return 0; 14 case 2: 15 printf("チョキ"); 16 return 0; 17 case 3: 18 printf("パー"); 19 return 0; 20 default: 21 printf("※再入力してください\n"); 22 } 23 } 24}

上記コードはCですが、これと同じ挙動をするようにHaskellで書きたいのです。

現状は以下の通りです。

Haskell

1loop :: IO() 2loop = do 3 putStr "[1] グー [2] チョキ [3] パー : " -- ここが問題の部分 4 x <- getLine 5 case x of 6 "1" -> putStrLn "グー" 7 "2" -> putStrLn "チョキ" 8 "3" -> putStrLn "パー" 9 x -> do 10 putStrLn "※再入力してください" 11 loop 12 13main :: IO() 14main = do 15 putStrLn "処理開始" 16 loop

基本的にはほぼ同じ挙動を再現するところまで来たのですが、ソースコード3行目のところで問題を起こしています。

私の予想では以下のように動くはずでした。

Haskell

1-- こう動いて欲しかった 2処理開始 3[1] グー [2] チョキ [3] パー : ※ここに入力できるようになる

それが実際に動かしてみると以下のようにプロンプトが表示さないでいます。

Haskell

1-- 何故かプロンプトが表示されない 2処理開始 3※プロンプトが表示されず、ここに入力できるようになっている

そして何らかの値を入力するとプロンプト部分の末尾に入力した値が表示されてしまいます。

Haskell

1-- 何故かプログラムの末尾に出力される 2処理開始 31 4[1] グー [2] チョキ [3] パー : グー

質問

どうしてこのような挙動になるのでしょうか?

アクションかIOモナドあたりの理解が足りていないのでしょうか?

長くなりましたが、ご回答よろしくお願いします。

Bearded-Ockham👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

バッファリングされているので手動でフラッシュする必要があります。

System.IO.hFlush を使います。

Haskell

1import System.IO (hFlush, stdout) 2 3loop :: IO () 4loop = do 5 putStr "[1] グー [2] チョキ [3] パー : " -- ここが問題の部分 6 hFlush stdout -- フラッシュする 7 x <- getLine 8 case x of 9 "1" -> putStrLn "グー" 10 "2" -> putStrLn "チョキ" 11 "3" -> putStrLn "パー" 12 x -> do 13 putStrLn "※再入力してください" 14 loop 15 16main :: IO () 17main = do 18 putStrLn "処理開始" 19 loop

投稿2020/05/19 16:27

kakkun61

総合スコア285

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

AGadget

2020/05/19 17:05

ご回答ありがとうございます! 早速試してみたところ、期待した通りの結果を得ることができました! > バッファリングされているので手動でフラッシュする必要があります。 恥ずかしながら「バッファリング」も「フラッシュ」も知らなかったので調べてきました。 今回の問題は「putStr関数の引数で指定された文字列がバッファ上に残ったままであり、getLine関数の処理が終わったタイミングでフラッシュされていた」ことが原因ということですね。 大変勉強になりました。 ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問