1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PureScriptで標準入力を扱うサンプルコード

Posted at

PureScriptで標準入力を扱う方法が案外分かりにくいのでサンプルコードを貼ってみます。

※ 以下のコードはPureScript 0.15.15で動作確認しています。

一行ずつ処理しなくて良い場合(かつMac/Linuxのみ)

大量のデータが入力されるユースケースでは標準入力を1行ずつ読み込んで都度処理しないとメモリを使い切ってしまう場合がありますが、そこまで大量でもない入力であれば以下のコードが一番シンプルです。

module Main where

import Prelude

import Effect (Effect)
import Effect.Console (log)
import Node.Encoding (Encoding(..))
import Node.FS.Sync (readTextFile)

main :: Effect Unit
main = do
  cs <- readTextFile UTF8 "/dev/stdin"
  log cs

ただし、/dev/stdinはWindowsでは使えないので、MacかLinuxで実行する場合しかこの方法は使えません。

プロジェクトの作成開始からの流れは以下のようになります。

spago init
spago install node-buffer node-fs
# src/Main.pursを編集
echo "hello" | spago run # テストを実行

一行ずつ処理しないといけない場合、もしくはWindowsにも対応したい場合

前述のプログラムと同様の処理をするコードは以下のようになります(node-readlineというパッケージを使うのがキモです)。

module Main where

import Prelude

import Effect (Effect)
import Effect.Console (log)
import Node.EventEmitter (on_)
import Node.Process (stdin)
import Node.ReadLine (createInterface, lineH)

main :: Effect Unit
main = do
  interface <- createInterface stdin mempty
  interface # on_ lineH \s ->
    log s

プロジェクト作成開始からの流れは以下です。

spago init
spago install node-event-emitter node-process node-readline
# src/Main.pursを編集
echo "hello" | spago run # テストを実行

このコードの派生型として、その他のユースケースのサンプルコードも以下に載せておきます。

ユーザーとインタラクティブにやり取りしたい場合

module Main where

import Prelude

import Effect (Effect)
import Effect.Class.Console (log)
import Node.EventEmitter (on_)
import Node.ReadLine (close, createConsoleInterface, lineH, noCompletion, prompt, setPrompt)

main :: Effect Unit
main = do
  interface <- createConsoleInterface noCompletion
  setPrompt "> " interface
  prompt interface
  interface # on_ lineH \s ->
    if s == "quit"
    then close interface
    else do log $ "Got " <> s
            prompt interface

先頭一行だけ無視したい場合

module Main where

import Prelude

import Effect (Effect)
import Effect.Console (log)
import Node.EventEmitter (on_, once_)
import Node.Process (stdin)
import Node.ReadLine (createInterface, lineH)

main :: Effect Unit
main = do
  interface <- createInterface stdin mempty
  interface # once_ lineH \_ ->
    interface # on_ lineH \s ->
      log s

標準入力から1行ずつではなくすべて一括で処理したい場合

module Main where

import Prelude

import Data.Array as A
import Data.String as S
import Effect (Effect)
import Effect.Console (log)
import Effect.Ref as Ref
import Node.EventEmitter (on_)
import Node.Process (stdin)
import Node.ReadLine (closeH, createInterface, lineH)

main :: Effect Unit
main = do
  readAll log

readAll :: (String -> Effect Unit) -> Effect Unit
readAll callbak = do
  inputStrings <- Ref.new []
  interface <- createInterface stdin mempty
  interface # on_ lineH \s ->
    Ref.modify_ (A.cons s) inputStrings
  interface # on_ closeH do
    cs <- (S.joinWith "\n" <<< A.reverse) <$> Ref.read inputStrings
    callback cs

このコードでは、一行ずつ読み込んだテキストをinputStringsという参照に溜め込んでいき、標準入力から読み込むものがなくなったら、コールバックとして渡された関数にまとめて渡しています。

もっと良い方法があったら教えてください。他にも「こんなときどうすればよいか?」といったご質問があれば(分かる範囲で)回答したいと思いますので、お気軽にコメントください。

参考にしたソース:
https://github.com/purescript-node/purescript-node-readline/blob/master/test/Main.purs

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?