2014-01-21 34 views
3

B-Prolog具有邏輯循環。例如,這就是我們可以計算出[1,2,3]總和:B-Prolog中帶有累加器的嵌套環

test1 :- 
    foreach(A in 1..3, [], ac(Sa, 0), (
      Sa^1 is Sa^0 + A 
     )), 
    writeln(sa(Sa)). 

?- test1. 
test1. 
sa(6) 
yes 

但是,當我嘗試用蓄電池兩個嵌套的循環,我得到的錯誤:

test2 :- 
    foreach(_A in 1..3, [Sb], ac(Sa, 0), (
      foreach(B in 1..3, [], ac(Sb, 0), (
        Sb^1 is Sb^0 + B 
       )), 
      writeln(sb(Sb)), 
      Sa^1 is Sa^0 + Sb 
     )), 
    writeln(sa(Sa)). 

?- test2. 
test2. 
*** error(invalid_argument,(+)/2) 

另一種變形,不包括銻在外環的局部變量列表:

test3 :- 
    foreach(_A in 1..3, [], ac(Sa, 0), (
      foreach(B in 1..3, [], ac(Sb, 0), (
        Sb^1 is Sb^0 + B 
       )), 
      writeln(sb(Sb)), 
      Sa^1 is Sa^0 + Sb 
     )), 
    writeln(sa(Sa)). 

?- test3. 
test3. 
sb(6) 
*** error(invalid_argument,(+)/2) 

它甚至有可能擁有與B-Prolog的蓄能器嵌套循環?

我的B-Prolog版本是8.0#1。

+0

在你的真實代碼中,內循環的目標是依賴於外循環的變量還是累加器?在這裏顯示的代碼中,'Sb'是不變的,可以預先計算。我想你的真實代碼並非如此? –

+0

是的,我只是提供了非常簡單的廢話代碼來顯示帶累加器的嵌套循環的問題。 –

+0

是的,我很懷疑。 :) –

回答

4

編譯時,程序運行正常。

| ? - cl(sergey)

Compiling::sergey.pl 
** Warning: Variable 'Sb' is treated as global in foreach (17-25). 
** Warning: Variable 'Sb' is treated as global in list_comprehension (36-38). 
compiled in 0 milliseconds 
loading... 

yes 
| ?- test1 
sa(6) 

yes 
| ?- test2 
sb(6) 
sb(6) 
sb(6) 
sa(18) 

yes 
| ?- test3 
sb(6) 
sb(6) 
sb(6) 
sa(18) 

解釋器肯定有問題。這累加器的東西是非常醜陋的,我從來沒有使用它。在B-Prolog的繼任者Picat中,您可以使用:=來「更新」變量。

test1 => 
     Sa = 0, 
     foreach(A in 1..3) 
      Sa := Sa+A 
     end, 
     writeln($sa(Sa)). 

    test2 => 
     Sa = 0, 
     foreach(_A in 1..3) 
      Sb := 0, 
      foreach(B in 1..3) 
       Sb := Sb+B 
      end, 
      writeln($sb(Sb)), 
      Sa := Sa+Sb 
     end, 
     writeln($sa(Sa)). 

更好的方法是使用列表理解。

test1 => 
     Sa = sum([A : A in 1..3]), 
     writeln($sa(Sa)). 

    test2 => 
     Sa = sum([Sb : _A in 1..3, Sb=sum([B : B in 1..3])]), 
     writeln($sa(Sa)). 

編譯器將求和編譯成使用':='的程序。由於列表實際上並沒有構建,所以沒有開銷。

1

http://www.probp.com/manual/node55.html似乎表明嵌套循環,扁平:

?-foreach(A in [a,b], I in 1..2, ac(L,[]), L^1=[(A,I)|L^0]). 
L = [(b,2),(b,1),(a,2),(a,1)] 

我們只需要恢復端內的-循環條件。看看這個工程:

test2 :- 
    foreach(A in 1..3, 
      B in 1..3, [], [ac(Sa, 0), ac(La, []) ac(Sb, 0)], (
        ( (La^0 = [] ; La^0 = [A]) % or just (La^0 = [A]) 
        ->        % same A, next B 
         Sa^1 is Sa^0, Sb^1 is Sb^0 + B 
        ;        % new A, B-loop has ended 
         Sa^1 is Sa^0 + Sb^0, writeln(sb(Sb^0)), Sb^1 is 0 + B 
        ), 
        La^1 = [A] 
       )), 
    Sa_final = Sa + Sb,       % process the final iteration 
    writeln(sa(Sa_final)). 

如果可以有重複的A S,只是指數起來的文檔顯示:

?-foreach((A,I) in ([a,b],1..2), ac(L,[]), L^1=[(A,I)|L^0]). 
L = [(b,2),(a,1)] 

I上的變化打破。 (未測試)。