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

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

Опять же, хорошо сам по себе, но, одним словом, он не компилируется.


person user1610406    schedule 26.09.2016    source источник


Ответы (2)


Меньше кольцевых развязок и не используются местные жители, ура

! get input as array of lines
: getinput ( -- input )
    { } [
        readln
        ! stop on .
        [ "." = ] keep swap
        [
            drop f
        ] [
             1array append
             t
        ] if
    ] loop
;

Я думаю, что ошибка была связана с тем фактом, что factor имеет довольно строгий эффект стека, даже с простым ветвлением.

person user1610406    schedule 27.09.2016
comment
Хорошо, только подумайте, что стек используется для тех же целей, что и локальные переменные и аргументы функций, а не как произвольная структура данных. Я бы предложил эти небольшие изменения: 1) dup "." = вместо [ "." = ] keep swap. 2) V{ } clone вместо { } и suffix! вместо 1array append. Вы можете сделать >array в конце, если в результате вам нужен массив. Таким образом, вы не выделяете новый при каждом добавлении. (Разница между суффиксом и добавлением применима с мутацией или без нее). - person fede s.; 30.09.2016

Причина, по которой вы не получаете никаких ошибок при написании кода в слушателе, заключается в том, что он скомпилирован наивным компилятором, который не оптимизирует код и не проверяет эффекты стека.

Например, в слушателе вы можете запустить 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
person Björn Lindqvist    schedule 30.09.2016
comment
Спасибо за разъяснения по оптимизации и тому, как проверяются эффекты стека, это действительно помогает. - person user1610406; 30.09.2016