Shell 在 Erlang 进程中多次打印输入
Shell within Erlang process prints input many times
我用 Erlang 为一种语言构建了一个 REPL。我运行它来自shell,像这样:
repl:main(Args).
它使用 io_getchars
读取,直到遇到 ;
,然后对其进行解析和词法分析:
getchar(eof) -> throw(eof);
getchar([C]) -> C.
getchar() -> getchar(io:get_chars("", 1)).
read_term() ->
case getchar() of
$; -> ";";
C -> [C|read_term()]
end.
一切都很好,但是与 repl 的交互看起来像这样:
willow% erl -name MyName
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]
Eshell V7.3 (abort with ^G)
(MyName)1> repl:main(Args).
Master is <0.39.0> in init_workers
1> map(fn(x)=x+1, '[1 2 3 4 5]);
ap(fn(x)=x+1, '[1 2 3 4 5]);
p(fn(x)=x+1, '[1 2 3 4 5]);
(fn(x)=x+1, '[1 2 3 4 5]);
fn(x)=x+1, '[1 2 3 4 5]);
n(x)=x+1, '[1 2 3 4 5]);
(x)=x+1, '[1 2 3 4 5]);
x)=x+1, '[1 2 3 4 5]);
)=x+1, '[1 2 3 4 5]);
=x+1, '[1 2 3 4 5]);
x+1, '[1 2 3 4 5]);
+1, '[1 2 3 4 5]);
1, '[1 2 3 4 5]);
, '[1 2 3 4 5]);
'[1 2 3 4 5]);
'[1 2 3 4 5]);
[1 2 3 4 5]);
1 2 3 4 5]);
2 3 4 5]);
2 3 4 5]);
3 4 5]);
3 4 5]);
4 5]);
4 5]);
5]);
5]);
]);
);
;
Delegated packet 0
Delegated packet 1
Delegated packet 2
Delegated packet 3
Delegated packet 4
(2 3 4 5 6)
2>
我也试过:
read_term(Acc) ->
case io:request(standard_io, {get_until, '', scanner, token, [1]}) of
{ok, EndToken={';;', _}, _} -> Acc ++ [EndToken];
{ok, Token, _} -> read_term(Acc ++ [Token]);
{error, token} -> {error, scanning_error};
{eof, _} -> Acc
end.
不幸的是,它具有相同的效果。
我不想看到我输入的字符串的所有可能的右移片段。是什么原因造成的,我该如何阻止它?
编辑:如果我从 shell 中 运行 改为 erl -noshell -eval 'repl:main()'
,则不会发生此打印。为什么?
您将不得不改用 io:get_line
,并遍历接收到的字符串。然后你必须决定如果接收到的字符串不包含任何“;”
例如:
1> Eval = fun(X) -> io:format("evaluation of ~p~n",[X]) end.
#Fun<erl_eval.6.50752066>
2> F = fun() ->
R = io:get_line("Enter a string : "),
L = string:tokens(R,";"),
[Eval(X) || X <- L]
end.
#Fun<erl_eval.20.50752066>
3> F().
Enter a string : map(fn(x)=x+1, '[1 2 3 4 5]);map(fn(x)=x+5, '[1 2 3 4 5]);uncomplete
evaluation of " map(fn(x)=x+1, '[1 2 3 4 5])"
evaluation of "map(fn(x)=x+5, '[1 2 3 4 5])"
evaluation of "uncomplete\n"
[ok,ok,ok]
4> F().
Enter a string : map(fn(x)=x+1, '[1 2 3 4 5]);
evaluation of " map(fn(x)=x+1, '[1 2 3 4 5])"
evaluation of "\n"
[ok,ok]
5>
[编辑]
io:get_chars/2
正在从 shell 输入中获取作为参数给出的字符数,在您的情况下为 1,其余的让其使用。 shell 不知道您将再次调用 io:get_chars/2
函数,因此它再次打印输入字符串的其余部分,并且在每次调用 [=16 时一次又一次地执行相同的操作=] 函数,这就是为什么你会看到这种奇怪的行为。
io:get_line/2
从 shell 和 return 中获取整个输入字符串(在 erlang 中它是一个整数列表),这就是为什么你有一个干净的行为在shellwindow中,那么就由你来选择你喜欢的算法来分析这个字符串了。我选择 string:tokens/2
是因为我尝试在它们存在时使用库函数,我认为它更容易阅读,并且不需要文档 :o)
如果您不想处理可能的错误输入,可以将 F/0 函数替换为
2> F = fun() ->
2> Rep = io:get_line("Enter a string : "),
2> [L,"\n"] = string:tokens(Rep,";"),
2> L
2> end.
它会和你的 read_term/0 函数做同样的事情(除了它删除最后一个 $;,但它会检查它是否存在):
3> F().
Enter a string : correct input;
"correct input"
4> F().
Enter a string : missing semi colon
** exception error: no match of right hand side value ["missing semi colon\n"]
5> F().
Enter a string : correct input; but extracharacters after semi colon
** exception error: no match of right hand side value ["correct input"," but extracharacters after semi colon\n"]
我用 Erlang 为一种语言构建了一个 REPL。我运行它来自shell,像这样:
repl:main(Args).
它使用 io_getchars
读取,直到遇到 ;
,然后对其进行解析和词法分析:
getchar(eof) -> throw(eof);
getchar([C]) -> C.
getchar() -> getchar(io:get_chars("", 1)).
read_term() ->
case getchar() of
$; -> ";";
C -> [C|read_term()]
end.
一切都很好,但是与 repl 的交互看起来像这样:
willow% erl -name MyName
Erlang/OTP 18 [erts-7.3] [source] [64-bit] [smp:4:4] [async-threads:10] [kernel-poll:false]
Eshell V7.3 (abort with ^G)
(MyName)1> repl:main(Args).
Master is <0.39.0> in init_workers
1> map(fn(x)=x+1, '[1 2 3 4 5]);
ap(fn(x)=x+1, '[1 2 3 4 5]);
p(fn(x)=x+1, '[1 2 3 4 5]);
(fn(x)=x+1, '[1 2 3 4 5]);
fn(x)=x+1, '[1 2 3 4 5]);
n(x)=x+1, '[1 2 3 4 5]);
(x)=x+1, '[1 2 3 4 5]);
x)=x+1, '[1 2 3 4 5]);
)=x+1, '[1 2 3 4 5]);
=x+1, '[1 2 3 4 5]);
x+1, '[1 2 3 4 5]);
+1, '[1 2 3 4 5]);
1, '[1 2 3 4 5]);
, '[1 2 3 4 5]);
'[1 2 3 4 5]);
'[1 2 3 4 5]);
[1 2 3 4 5]);
1 2 3 4 5]);
2 3 4 5]);
2 3 4 5]);
3 4 5]);
3 4 5]);
4 5]);
4 5]);
5]);
5]);
]);
);
;
Delegated packet 0
Delegated packet 1
Delegated packet 2
Delegated packet 3
Delegated packet 4
(2 3 4 5 6)
2>
我也试过:
read_term(Acc) ->
case io:request(standard_io, {get_until, '', scanner, token, [1]}) of
{ok, EndToken={';;', _}, _} -> Acc ++ [EndToken];
{ok, Token, _} -> read_term(Acc ++ [Token]);
{error, token} -> {error, scanning_error};
{eof, _} -> Acc
end.
不幸的是,它具有相同的效果。
我不想看到我输入的字符串的所有可能的右移片段。是什么原因造成的,我该如何阻止它?
编辑:如果我从 shell 中 运行 改为 erl -noshell -eval 'repl:main()'
,则不会发生此打印。为什么?
您将不得不改用 io:get_line
,并遍历接收到的字符串。然后你必须决定如果接收到的字符串不包含任何“;”
例如:
1> Eval = fun(X) -> io:format("evaluation of ~p~n",[X]) end.
#Fun<erl_eval.6.50752066>
2> F = fun() ->
R = io:get_line("Enter a string : "),
L = string:tokens(R,";"),
[Eval(X) || X <- L]
end.
#Fun<erl_eval.20.50752066>
3> F().
Enter a string : map(fn(x)=x+1, '[1 2 3 4 5]);map(fn(x)=x+5, '[1 2 3 4 5]);uncomplete
evaluation of " map(fn(x)=x+1, '[1 2 3 4 5])"
evaluation of "map(fn(x)=x+5, '[1 2 3 4 5])"
evaluation of "uncomplete\n"
[ok,ok,ok]
4> F().
Enter a string : map(fn(x)=x+1, '[1 2 3 4 5]);
evaluation of " map(fn(x)=x+1, '[1 2 3 4 5])"
evaluation of "\n"
[ok,ok]
5>
[编辑]
io:get_chars/2
正在从 shell 输入中获取作为参数给出的字符数,在您的情况下为 1,其余的让其使用。 shell 不知道您将再次调用 io:get_chars/2
函数,因此它再次打印输入字符串的其余部分,并且在每次调用 [=16 时一次又一次地执行相同的操作=] 函数,这就是为什么你会看到这种奇怪的行为。
io:get_line/2
从 shell 和 return 中获取整个输入字符串(在 erlang 中它是一个整数列表),这就是为什么你有一个干净的行为在shellwindow中,那么就由你来选择你喜欢的算法来分析这个字符串了。我选择 string:tokens/2
是因为我尝试在它们存在时使用库函数,我认为它更容易阅读,并且不需要文档 :o)
如果您不想处理可能的错误输入,可以将 F/0 函数替换为
2> F = fun() ->
2> Rep = io:get_line("Enter a string : "),
2> [L,"\n"] = string:tokens(Rep,";"),
2> L
2> end.
它会和你的 read_term/0 函数做同样的事情(除了它删除最后一个 $;,但它会检查它是否存在):
3> F().
Enter a string : correct input;
"correct input"
4> F().
Enter a string : missing semi colon
** exception error: no match of right hand side value ["missing semi colon\n"]
5> F().
Enter a string : correct input; but extracharacters after semi colon
** exception error: no match of right hand side value ["correct input"," but extracharacters after semi colon\n"]