Входное предложение для цикла не соответствует ожидаемому эффекту
Я пытаюсь написать текстовый редактор, чтобы имитировать формат ввода ed
, В ed
, вы пишете свой ввод по одной строке за раз и заканчиваете, когда вы вводите один .
на линии. Вот что я придумал:
0 [
[ readln [ "." = not ] keep swap ] dip 1 + swap
] loop
nip 1 - narray
Этот фрагмент получает ввод от пользователя по одной строке за раз, останавливается, когда достигает одной точки, и возвращает массив строк.
Я не получаю никаких ошибок, когда это само по себе, но как только я пытаюсь выразить это одним словом:
: getinput ( -- input )
0 [
[ readln [ "." = not ] keep swap ] dip 1 + swap
] loop
nip 1 -
narray
;
Я получаю следующую ошибку:
The input quotation to “loop” doesn't match its expected effect
Input Expected Got
[ ~quotation~ dip 1 + swap ] ( ... -- ... ? ) ( x -- x x x )
(U) Quotation: [ c-to-factor -> ]
...
Я думаю, что это может быть связано с тем, что компилятор не заботится об объявлении стека, когда оно не в слове, а не когда оно есть. Это недовольно модифицировать стек под циклом? Я знаю о call( )
, но если мне нужно использовать это здесь, как?
Изменить: я также только что попробовал следующее:
:: getinput ( -- input )
0 :> count!
[ [ "." = not ] keep swap ]
[ readln count 1 + count! ] do while
drop count 1 - narray
;
Я получаю похожую ошибку, однако эффекты стека немного отличаются:
The input quotations to “while” don't match their expected effects
Input Expected Got
[ ~quotation~ keep swap ] ( ..a -- ..b ? ) ( x -- x x )
[ _ 1 load-locals readln 0 get-local local-value 1 + 0 get-local... ( ..b -- ..a ) ( -- x )
(U) Quotation: [ c-to-factor -> ]
...
Опять же, хорошо само по себе, но одним словом, оно не компилируется.
2 ответа
Меньше кольцевой и не использует местные жители, хузы
! get input as array of lines
: getinput ( -- input )
{ } [
readln
! stop on .
[ "." = ] keep swap
[
drop f
] [
1array append
t
] if
] loop
;
Я думаю, что ошибка была связана с тем, что фактор имеет довольно строгий эффект стека, даже с простым ветвлением.
Причина, по которой вы не получаете никаких ошибок при написании кода в слушателе, заключается в том, что он компилируется с помощью простого компилятора, который не оптимизирует код и не проверяет эффекты стека.
Например, в слушателе вы можете запустить clear
но какой эффект стека имеет слово? Это зависит от того, сколько предметов в хранилище данных! Если есть три, эффект ( x x x -- )
, два ( x x -- )
или один ( x -- )
, Попробуй и поставь clear
одним словом и скомпилируйте. Вы не можете этого сделать, потому что оптимизирующий компилятор понятия не имеет, каким будет его эффект стека.
Ваш код имеет ту же проблему:
0 [
[ readln [ "." = not ] keep swap ] dip 1 + swap
] loop
Эффект стека зависит от того, сколько строк пользователь вводит до периода. Так может быть ( -- x x x )
, ( -- )
(ноль строк), ( -- x )
и так далее. Сообщение об ошибке, которое оно показывает, возможно, не совсем ясно, но эта проблема является его источником.
Способ, которым вы переписали цикл, Factor может статически определить его эффект стека и скомпилировать ваш код:
[ readln [ "." = ] keep swap [ drop f ] [ 1array append t ] if ] infer.
( x -- x x )
Обратите внимание, что loop
это низкоуровневые слова для реализации итерации, и вам почти никогда не придется их использовать. Например, вы можете использовать produce
комбинатор:
[ readln dup "." = not ] [ ] produce