io:format(io:get_line("")).
必要な道具立ては io モジュールのページに揃っている。
ここでは2つの関数呼び出しが行われている。
get_line/1 は、標準入力から1行分のデータを読み、成功すれば文字列を返す。
"\n"
(ユーザが叩いたEnterキーに相当する)も含まれる。format/1 は、標準出力に出力する関数。文字列以外に、アトムなど印字可能なデータを渡すこともできる。
2つの関数呼び出しの間を変数でつなぐ(1行目が代入文になる)書き方もあるが、 非推奨なのでここでは紹介しないでおく。
Erlang では、関数 read は、(他の言語と違って)生データの読み込みをせず、代わりに、term (Erlangの任意のデータ)を読み込む。 io:read("").
これもREPL上では気軽に使える関数だが、ここでは紹介するにとどめておく。
io:format
の代わりに io:fwrite
も同じように使える ( /1 /2 /3 の3種類のAPIが用意されている点も同じ)。
読み込んだ文字列をそのまま io:format/1 に渡した場合、 もしその文字列の中に ~n
、 ~s
などの(io:format で解釈される)フォーマット文字列が含まれているとエラーになる可能性もあるので、
文字列 S を印字するときに、 io:format(S).
の代わりに io:format("~s",[S]).
と書くほうが安全だろう。
:io.format(:io.get_line(""))
上記のErlangで使用したモジュール・関数をそのまま借用する。
.
が使われる。.
(ピリオド)は不要。関数呼び出しの組み合わせでプログラムを作るこれらの言語では、 関数の結果を別の関数に引数として渡す、という場面が多く、そのコードは、 fnca(fncb(fncc(fncd())))
のような形になり、
といった問題の原因になる。それに対する解決策として、Elixirでは、 パイプ演算子 |>
が用意されている。上記のコードをパイプ演算子で表現すると、
:io.get_line("")|>:io.format()
こうなる(左から右にデータおよび制御が流れていく)。
|>
の右側に書かれた関数呼び出しは、 |>
の左辺の式の値を、第1引数の値として受け取る。詳しくは、 たとえば公式の解説ページを参照。|>
を使った記法を並べて提示するが、いずれ後者で書ける所は後者のみで 示していくことになることを了解されたい。IO.gets("")|>:IO.puts()
また、
IO.read(:stdio,:line)
という関数もあり、行単位の入力や、ファイル全体の入力にも使える。
端末(標準入力)から1行読み取って画面に表示する、という動作を 繰り返す、ただし、入力終了(EOFと一般に呼ばれる)ならばそれ以上 繰り返さない、という判断を行う。
こういった関数型言語で再帰を実現する書き方は大別すると2つあるので それを両言語で示す。
ただし、以下に示すプログラム(多くの解説ページにこれと同様の形で提示されているが)は 現在動作が確認できていない。 ErlangおよびElixir処理系が eof 事象を受け渡しできていないようだ (が、プログラムは参考のためここに提示しておく)。
%% パターンマッチングで末尾判定を行うバージョン
-module(oumu).
-export([main/1]).
main(_)->ans(io:get_line("")).
ans(eof)->ok; % 或いはここで init:stop() を呼ぶ
ans(Str)->io:format(Str),
ans(io:get_line("")).
%% case 構文で末尾判定を行うバージョン
-module(oumu).
-export([main/1]).
main(_)->ans().
ans()->
case io:get_line("") of
eof->init:stop();
Line->io:format(Line), ans().
## パターンマッチングで末尾判定を行うバージョン
defmodule Oumu do
def ans(), do: ans(IO.gets(""))
defp ans(:eof), do: :ok
defp ans(str), do: IO.puts(str); ans(IO.gets(""))
end
## case 構文で末尾判定を行うバージョン
defmodule Oumu do
def ans() do
case IO.gets("") do
:eof-> :ok
line-> IO.puts(line); ans()
end
end
end
前節に示したプログラムを、空行入力で終了するよう変更したもの。 前節のうち、case 構文で末尾判定を行うバージョンについて再掲した。
-module(oumu).
-export([main/1]).
main(_)->ans().
ans()->
case io:get_line("") of
eof->init:stop(); % この節も一応残しておく
"\n"->init:stop();
Line->io:format(Line), ans().
end.
defmodule Oumu do
def ans() do
case IO.gets("") do
:eof-> :ok
"\n"-> :ok
line-> IO.puts(line); ans()
end
end
end
Oumu.ans()
フォーマット文字列での後ろに、そこに埋め込むべきデータを並べる使い方だが、CやRubyでは関数が可変引数として用意されていて、括弧内にカンマ区切りで並べていたが、
Erlang, Elixir では、関数名とアリティ(引数の数)を対にして (format/2 のように)扱ってそれで関数を区別する方法なので、 括弧の中に並べるのではなく、リストとして1つにまとめてformatに渡す。
変換指示を “%s”, “%d” のようにパーセント文字先行させる言語が多いが、io:format() では “~s”, “~d” のように チルダ先行(改行も “~n” で指示する)。