2014-02-18 32 views
0

我的列表(其中又包含列表)包含許多不同類型的元素(obj1(),obj2(),obj3 ..)。我想訪問這個列表中的每個元素,只有當我正在訪問的元素的類型爲obj2(_)時纔會執行某些操作。如何檢查列表中元素的類型

listObj = [[ obj1(_), obj2(_), obj1(_) ], 
      [ obj3, obj3, obj2(_), obj1(_)]], 

foreach ((X, listObj)), 
%% if X is obj2(_) -> doSomething using x's _ value, 
%% otherwise skip this element 
). 

回答

3

使用列表通常暗示了一個糟糕的表現。但是,如果您無法避免此表示形式,則多個系統可能會對列表提供flatten/2庫謂詞。假設示例中列表的列表已經平鋪,您應該可以編寫一個簡單的遞歸謂詞來遍歷列表並處理滿足條件的每個元素。例如:

process([]). 
process([Element| Elements]) :- 
    ( Element = obj2(Arg) -> 
     do_something(Arg) 
    ; true 
    ), 
    process(Elements). 

但是,具體情況取決於您未指定的幾個因素。例如,如果處理obj2(_)元素失敗,那麼這意味着什麼?處理列表失敗(如上面簡述的謂詞)?繼續下一個元素?列表元素是獨立的還是可以共享變量的?某些Prolog系統還提供了foreach/2forall/2謂詞,這些謂詞對於緊湊(但不一定更高效)的解決方案可能有用。

1

我認爲這只是一個基本的遞歸問題 - 如何遍歷列表,並在頭上使用模式匹配。如果是的話,這應該做

% case 1 - end recursion 
listiter([]). 

% case 2 - list head obj2 matches 
listiter([obj2(Obj_2_Value)|T]) :- 
    write(Obj_2_Value), nl, 
    listiter(T). 

% case 3 - case 2 failed, just recurse, ignoring head 
listiter([_|T]) :- 
    listiter(T). 

在你的「真實」的代碼,替換了「寫入/ NL」不管你要真的做OBJ2()的值謂詞。

?listiter([obj1(brown), obj2(hello), obj3(fred), obj2(stack), obj4(bun), obj2(overflow)]). 
hello 
stack 
overflow 
true . 

或更短的方式,使用內置MAPLIST/1:列出的

% match if item is obj2() 
dosomething(obj2(Obj_2_Value)) :- 
    write(Obj_2_Value), nl. 

% not object 2 - still return true, but don't do anything 
dosomething(_). 


?- maplist(dosomething, [obj1(brown), obj2(hello), obj3(fred), obj2(stack), obj4(bun), obj2(overflow)]). 
hello 
stack 
overflow 
true . 
0

更簡單的方法(但請注意:變量開始大寫):與

nested_member(V, X) :- 
    member(T, X), 
    (is_list(T) -> nested_member(V, T) ; V = T). 

..., flatten(ListObj, F), member(obj2(V), F), process(V), ... 

爲了避免扁平化的列表,我們必須做出斷言,並引入遞歸

?- nested_member(obj2(V),[[1,[2,obj2(3),a],obj2(b),4]]). 
V = 3 ; 
V = b ; 
false.