PureScript を使用した標準入力 (stdin) からの読み取り


ここ数週間、PureScript の学習を再開しました.私はこの言語が大好きです.これは関数型プログラミングの真髄ですが、たとえば TypeScript と比較してコミュニティやライブラリが不足しているため、悲しいことにサイド プロジェクトで使用するのが非常に難しくなっています.

オンラインでいくつかのチャレンジを行っているときに、 stdin から入力文字列を取得する必要がありました.このケースはどこにも詳しく書かれていないことがわかったので、新しいブログ記事を書いてみませんか? 🙃

まず、標準入力 (stdin) から読み取るには、ライブラリ purescript-node-process が必要です.このライブラリは、stdin (単純な読み取り可能なストリーム) である Readable を公開します.これは、関数を作成するための重要なコンポーネントになります.単純なストリームを扱っているので、作成したいのは、同じストリームを受け取り、新しい文字列を返す関数です.

import Prelude
import Control.Monad.ST.Class (liftST)
import Control.Monad.ST.Ref as STRef
import Data.Either (Either(..))
import Effect (Effect)
import Effect.Aff (effectCanceler, launchAff_, makeAff)
import Effect.Aff.Class (class MonadAff, liftAff)
import Effect.Class (liftEffect)
import Effect.Console (log)
import Node.Encoding (Encoding(..))
import Node.Process (stdin)
import Node.Stream (Readable, destroy, onDataString, onEnd, onError)

-- Accumulate a readable stream inside a string.
streamAccumulator :: forall m r. MonadAff m => Readable r -> m String
streamAccumulator r =
  liftAff <<< makeAff
    $ \res -> do
        -- Create a mutable reference using `purescript-st`.
        inputRef <- liftST $ STRef.new ""

        -- Handle the `onDataString` event using
        -- the UTF8 encoding.
        onDataString r UTF8 \chunk ->
          void <<< liftST $ STRef.modify (_ <> chunk) inputRef

        -- Handle the `onEnd` event.
        onEnd r do
          input <- liftST $ STRef.read inputRef
          res $ Right input

        -- Handle the `onError` event.
        onError r $ Left >>> res

        -- Return a `Canceler` effect that will
        -- destroy the stream.
        pure $ effectCanceler (destroy r)

-- Execute the program.
main :: Effect Unit
main =
  launchAff_ do
    input <- streamAccumulator stdin
    liftEffect $ log input


これは少し面倒に見えますが、実際には簡単です.ストリームを処理するプロセスは「イベント駆動型」であるため、onDataString イベントがトリガーされるたびに、安全な可変文字列 ( purescript-st から) を使用して入力を蓄積します.このプロセス全体は非同期です.つまり、onEnd イベント (何か問題が発生した場合は onError) が実際に蓄積された文字列を返すまで待機する必要があります.効果モナド Aff は、 makeAff を通してこれを解決します. res コールバックは Either パラメータで呼び出す必要があり、このコールバックがトリガーされた場合にのみ、プログラムは実行を継続できます.

平和✌️