简体   繁体   中英

Input quotation to loop doesn't match expected effect

I'm trying to write a text editor to mimic the input format of ed . In ed , you write your input one line at a time and finish when you input a single . on a line. Here's what I came up with:

0 [
    [ readln [ "." = not ] keep swap ] dip 1 + swap
] loop
nip 1 - narray

This snippet gets input from the user one line at a time, stops when it reaches a single dot, and returns an array of strings.

I don't get any errors when it's on its own, but as soon as I try to put it into a word:

: getinput ( -- input )
    0 [
        [ readln [ "." = not ] keep swap ] dip 1 + swap
    ] loop
    nip 1 -
    narray
;

I get the following error:

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 -> ]
...

I think it might be something to do with the compiler not caring about the stack declaration when it's not in a word as opposed to when it is. Is it unhappy about modifying the stack underneath loop? I know about call( ) , but if I need to use it here, how?


Edit: I also just tried the following:

:: getinput ( -- input )
    0 :> count!
    [ [ "." = not ] keep swap ]
    [ readln count 1 + count! ] do while
    drop count 1 - narray
;

I get a similar error, however the stack effects are slightly different:

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 -> ]
...

Again, fine on its own, but in a word, it doesn't compile.

Less roundabout and doesn't use locals, huzzah

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

I think the error had to do with the fact that factor has pretty strict stack effect stuff, even with simple branching.

The reason you don't get any errors when writing the code in the listener is because it is compiled with the naive compiler which doesn't optimize the code and doesn't check the stack effects.

For example, in the listener you can run clear but what stack effect does the word has? It depends on how many items there are on the datastack! If there are three the effect is ( xxx -- ) , two ( xx -- ) or one ( x -- ) . Try and put clear in a word and compile it. You can't because the optimizing compiler has no idea what its stack effect would be.

Your code has the same problem:

0 [
    [ readln [ "." = not ] keep swap ] dip 1 + swap
] loop

It's stack effect depends on how many lines the user enter before the period. So it could be ( -- xxx ) , ( -- ) (zero lines), ( -- x ) and so on. The error message it is showing is perhaps not entirely clear, but this issue is the source of it.

The way you have rewritten the loop, Factor can statically determine its stack effect and compiles your code:

[ readln [ "." = ] keep swap [ drop f ] [ 1array append t ] if ] infer.
( x -- x x )

Note also that loop is a low-level words for implementing iteration and you should almost never need to use it. For example, you could use the produce combinator:

[ readln dup "." = not ] [ ] produce

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM