2016-09-26 7 views
2

J'essaye d'écrire un éditeur de texte pour imiter le format d'entrée de ed. Dans ed, vous écrivez votre entrée une ligne à la fois et terminez lorsque vous entrez un seul . sur une ligne. Voici ce que je suis venu avec:La citation d'entrée à la boucle ne correspond pas à l'effet attendu

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

Cet extrait obtient l'entrée de l'utilisateur une ligne à la fois, arrête quand il atteint un point unique, et retourne un tableau de chaînes.

Je ne reçois pas d'erreurs quand il est lui-même, mais dès que je tente de le mettre en un mot:

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

Je reçois l'erreur suivante:

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

Je pense que cela pourrait être quelque chose à faire avec le compilateur ne se soucie pas de la déclaration de la pile quand ce n'est pas dans un mot par opposition à quand il l'est. Est-il mécontent de modifier la pile sous la boucle? Je sais environ call(), mais si j'ai besoin de l'utiliser ici, comment?


Edit: Je viens aussi essayé ce qui suit:

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

je reçois une erreur semblable, mais les effets de la pile sont légèrement différentes:

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

Encore une fois, bien sur son propre , mais en un mot, il ne compile pas.

Répondre

1

Moins rond-point et ne pas utiliser les habitants, huzzah

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

Je pense que l'erreur avait à voir avec le fait que ce facteur a assez strict stuff effet de cheminée, même avec une ramification simple.

+1

Nice, il suffit de penser que la pile est utilisé pour les mêmes fins que vars locales et arguments de la fonction, et non comme une structure de données arbitraires. Je suggérerais ce tweaks mineur: 1) 'dup". " = 'au lieu de' ["." =] garder le swap'. 2) 'V {} clone' au lieu de' {} 'et' suffix! 'Au lieu de' 1array append'. Vous pouvez faire '> array' à la fin si vous avez besoin d'un tableau en conséquence. De cette façon, vous n'en attribuez pas de nouveau à chaque ajout. (La différence entre suffixe et append est applicable avec ou sans mutation). –

1

La raison pour laquelle vous n'obtenez aucune erreur lors de l'écriture du code dans l'écouteur est qu'il est compilé avec le compilateur naïf qui n'optimise pas le code et ne vérifie pas les effets de la pile. Par exemple, dans l'écouteur, vous pouvez exécuter clear mais quel est l'effet de pile du mot? Cela dépend du nombre d'éléments sur la base de données! S'il y en a trois, l'effet est (x x x --), deux (x x --) ou un (x --). Essayez de mettre clear en un mot et compilez-le. Vous ne pouvez pas parce que le compilateur d'optimisation n'a aucune idée de ce que son effet de pile serait.

Votre code a le même problème:

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

Il est l'effet pile dépend du nombre de lignes l'utilisateur d'entrer avant la période. Donc, il pourrait être (-- x x x), (--) (lignes zéro), (-- x) et ainsi de suite. Le message d'erreur qu'il montre n'est peut-être pas tout à fait clair, mais ce problème en est la source.

La façon dont vous avez réécrit la boucle, le facteur peut statiquement déterminer son effet de pile et compile votre code:

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

Notez également que loop est un des mots de bas niveau pour la mise en œuvre itération et vous avez besoin presque jamais pour l'utiliser. Par exemple, vous pouvez utiliser le produce Combinator:

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

Merci pour la clarification sur l'optimisation et comment les effets de pile sont vérifiés, cela aide vraiment. – user1610406