Входное предложение для цикла не соответствует ожидаемому эффекту

Я пытаюсь написать текстовый редактор, чтобы имитировать формат ввода 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
Другие вопросы по тегам