Сложно-рекурсивные стековые эффекты?

USING: accessors html.parser.analyzer io kernel math namespaces
  present regexp sequences ;
IN: all-roads-to-wiki

SYMBOL: G

: match-good-pages ( a -- ?/f )
  R/ \/wiki\/[^:]*$/ first-match ;

: filter-urls ( tags -- urls )
  find-hrefs [ present ]     map
  [ match-good-pages ]       filter
  [ match-good-pages seq>> ] map ;

: findpath ( url -- url )
  G get =
  [
     ! false
  ]
  [ scrape-html nip
    [
      dup "title" find-by-name drop 1 + swap nth
      text>> R/ - Wikipedia,/ re-split first print
    ]
    [
      "bodyContent" find-by-id-between filter-urls [ findpath ] map
    ] bi
  ] if ; inline recursive

: allroads-entry ( -- a )
  readln "http://en.wikipedia.org/wiki/" prepend G set-global
  "enwp.org/Special:Random" findpath ; inline

Приведенный выше код будет повторяться по каждой ссылке в Википедии, пока не найдет ту, которую ищет.

Это нормально, потому что (надеюсь) findpath в конечном итоге "вернется" (т.е. не вызовет себя снова) и оставит огромную вложенную структуру данных в стеке. Но когда я пытаюсь скомпилировать это, я получаю unbalanced-recursion ошибка:

В рекурсивном слове "findpath" стек имеет неправильную высоту

unbalanced-recursion: Брошенный, когда вывод эффекта стека определяет, что у встроенного рекурсивного слова есть неправильное объявление эффекта стека.

Независимо от того, что я делаю, Фактор (понятно) жалуется, что эффект стека не совпадает. Что мне нужно сделать, чтобы это правильно восстановилось?

1 ответ

Решение

Посмотри внимательно на find-path слово. Я добавлю комментарии, чтобы вы могли видеть, что находится в стеке:

: findpath ( url -- url )
    ! 1 item: { url }
    G 
    ! 2 items: { url G }
    get 
    ! 2 items: { url value-of-G }
    =
    ! 1: item { t/f }
    [
       ! 0 items!!!!
       ! false
    ]
    [ scrape-html nip
        [
            dup "title" find-by-name drop 1 + swap nth
            text>> R/ - Wikipedia,/ re-split first print
        ]
        [
            "bodyContent" find-by-id-between filter-urls 
            [ findpath ] map
        ] bi
    ] if ; inline recursive

if комбинатор потребляет последний элемент в стеке, поэтому этот код не может работать. Вот рабочий код для findpath слово:

: page-title ( seq -- title )
    dup "title" find-by-name drop 1 + swap nth
    text>> R/ - Wikipedia,/ re-split first ;

: page-links ( seq -- links )
    "bodyContent" find-by-id-between filter-urls ;

: scrape-en-wiki-url ( wiki-url -- seq )
    "https://en.wikipedia.org" prepend
    dup print flush scrape-html nip ;

: found-url? ( wiki-url -- ? )
    G get [ = ] [ drop t ] if* ;

: findpath ( wiki-url -- seq/f )
    dup found-url?
    [ drop f G set f ] [
        scrape-en-wiki-url
        [ page-title print flush ] [
            page-links [ findpath ] map
        ] bi
    ] if ; inline recursive

Также взгляните на словарь Википедии, который предназначен для подобных задач.

Другие вопросы по тегам