2016-04-10 13 views
2
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エラーを取得:

The recursive word “findpath” leaves with the stack having the wrong height

unbalanced-recursion : Thrown when stack effect inference determines that an inline recursive word has an incorrect stack effect declaration.

をどんなに私は何をすべきか、ファクター(当然)が、最大一致しないスタック効果文句ありません。これを適切に再発させるにはどうすればよいですか?

+0

偽のブランチに 'drop f'を、正しく理解していれば、リストの偽物を取り除くために' sift'を使います。 2つ目は 'G get ='の前に 'dup'がないと思います(=がURLを消費するため)。 3-再帰が終了するのは確かですか?リストは永遠に成長しないでしょうか? –

+0

これは、リンクのグラフ上での深さ優先検索のようなものではありませんか?どこかでサイクルが見つかると、永遠にそこに詰め込まれるでしょう! @fedes。 –

+0

@fedes。あなたはおそらく正しいでしょうが、再帰的ソリューションのように動作するはずです:http://codegolf.stackexchange.com/questions/34662/find-a-route-between-ww-wikipedia-articles – cat

答えて

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 

はまた、これらのようなタスクのためのものですWikipedia vocabを見てみましょう。

関連する問題