昨日のHaskellハンズオン でIOモナドを学びました。 アイデアがあったものの、イベント中に実装が間に合わなかったので改めて時間を取って実装をしてみました。
改良点すべき点は多いのですが、とりあえず動くようになったので公開してみます。
作ったもの
英語学習用のCLIツール。
日本語に対応する英語を入力すると正解か不正解か、不正解の場合はそのDiffが表示される。
最近、瞬間英作文の書籍を使って英語の勉強をしているのですが、音読だと時制や単数・複数の扱いが曖昧なまま流してしまうので、コンソールで入力して正確な作文が出来ているのかチェックしてみることにしました。
紙に書くと時間がかかるので、キーボード入力がちょうどいいのではと思った次第です。
どんどん話すための瞬間英作文トレーニング (CD BOOK)
- 作者: 森沢洋介
- 出版社/メーカー: ベレ出版
- 発売日: 2006/10/25
- メディア: 単行本
- 購入: 80人 クリック: 383回
- この商品を含むブログ (173件) を見る
コード
import Control.Monad (forM_) import Data.Maybe import System.IO (hFlush, stdout) import System.Console.ANSI import System.Console.Readline (readline) import Data.Algorithm.Diff (getGroupedDiff, Diff(First, Second, Both)) sentences :: [(String, String)] sentences = [("これはリンゴです。", "This is an apple.") ,("彼は東京に住んでいます。", "He lives in Tokyo.") ,("これらの本はとても高い", "These books are very expensive.") ] main :: IO () main = examination examination :: IO () examination = forM_ sentences $ \(question, answer) -> do putStrLn question hFlush stdout maybeLine <- readline "> " case maybeLine of Nothing -> return () Just line -> putResult answer line putResult :: String -> String -> IO () putResult expected actual = do if expected == actual then putStrLn "✅" else do putStrLn "=====" putStrLn expected mapM_ showDiff $ getGroupedDiff actual expected putStrLn "" putStrLn "" showDiff :: Diff String -> IO () showDiff (First x) = do setSGR [SetUnderlining SingleUnderline] setSGR [SetColor Foreground Dull Red] putStr x setSGR [Reset] showDiff (Second x) = do setSGR [SetUnderlining SingleUnderline] setSGR [SetColor Foreground Dull Green] putStr x setSGR [Reset] showDiff (Both x _) = do
要素技術など
Readline
Ctrl-a
やCtrl-h
などを使うために、readline
のライブラリを使いました。
OSXのインストールに手間取ったのですが、下記の方法で解決しました。
ansi-terminal
文字色を設定するために使用
diff
O(ND) diffアルゴリズムを使用するために使用
Diff: O(ND) diff algorithm in haskell.
エディットグラフを使用したdiffアルゴリズムとO(ND)法による実装は以下が詳しかったです。
http://hp.vector.co.jp/authors/VA007799/viviProg/doc5.htm
今回はライブラリを使ったのですが、このアルゴリズムを独自実装するのもまた楽しそうです。
感想
これまでHaskellを勉強していても、IOが必要となるアプリを作っていなかったのでいい機会となりました。
Haskellでも手続き的な記述をすることができ、これなら自分もHaskellでも意外と実用的なコード書けそうな感覚を持ちました。 引き続き実装進めていきます。
今後のTODO
- 単語レベルでdiffを取るようにする
- 外部ファイルから学習用データを読み込めるようにする
- 正答数を出力する
- 回答までの時間を計測する
- ランダムな順番で出題できるようにする
- 結果を保存し、間違えた問題のみ再度テスト出来るようにする
- Ctrl-Dで終了できるようにする