1 2 3 4 5 6 7 8 9 | > swipl Welcome to SWI-Prolog (threaded, 64 bits, version 9.0.3) SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software. Please run ?- license. for legal details. For online help and background, visit https://www.swi-prolog.org For built-in help, use ?- help(Topic). or ?- apropos(Word). ?- |
1 2 3 4 5 | % This is a single line comments /* This is a set of multiple line comments that continue until we hit the sequence */ |
1 2 3 4 5 6 7 8 9 10 | % Hello World example ?- writeln('Hello, World!'). % Without a new line Hello, World! true. ?- writeln('Hello, World!'), nl. % With a new line Hello, World! true. |
1 2 3 4 5 6 7 | % Facts are relationships between one or more objects that are always true man(keith). % keith is a man programmer(keith). % keith is a programmer likes(keith, java). % keith likes java proficient_in(keith, java, high). % keith has high proficiency in java drinks_coffee(keith). % keith drinks coffee |
1 2 3 4 5 6 7 8 9 10 11 | % Some basic facts stored in a file called 'test.pl' man(keith). programmer(keith). likes(keith, java). likes(keith, python). likes(keith, lisp). likes(keith, prolog). dislikes(keith, vb). dislikes(keith, cobol). dislikes(keith, fortran). |
1 2 3 4 5 6 7 8 9 10 11 12 | > swipl Welcome to SWI-Prolog (threaded, 64 bits, version 9.0.3) : : ?- [test]. % Load the file using [<filename>]. true. % true tells us the file has been loaded ?- man(keith). % Is keith a man true. ?- man(fred). % is free a man false. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ?- likes(keith, X). % Asking what does keith like X = java ; % Enter % for next response X = python ; X = lisp ; X = prolog. ?- dislikes(X, java). % We have no fact that states anyone dislikes Java false. ?- dislikes(X, Y). % Asking who dislikes what X = keith, Y = vb ; % keith dislikes vb, enter ; for next X = keith, Y = cobol ; % keith dislikes cobol, enter ; for next X = keith, Y = fortran. % keith dislikes fortran, no more solutions |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | % Atoms Strings of letters, digits % and the underscore character ‘_', % starting with a lower-case letter a123 a_123 a_1_2_3 keith keith_2 keith_sterling % Atoms can also be strings of characters enclosed in single quotes. % Useful if your atom name starts with a capital letter 'Keith' 'London' 'A_1234' |
1 2 3 4 5 6 7 8 9 10 11 12 13 | % Numbers are typically integers, % Floating points are implementation dependent because Prolog is about symbolic logic % Integers 10 -10 100 16383 % Max int -16383 % Min int % Real Numbers 3.142 -23.78 |
1 2 3 4 5 6 7 8 9 10 | % Variables are named like atoms, but they start with an % upper case character or underscore _ X Student Name _Y % Anonymous Variables are just a single underscore _ |
1 2 3 4 5 6 7 8 9 10 | % Structures are data objects thats contain multiple components % there structure is made up of a functor and multiple arguments % To represent the data February 29th 1980 we would use one of the following date(29, 2, 1980). date(29, Feb, 1980). % Or we could represent a triangle made of 3 structures triangle(point(1,1), point(3, 5), point(1, 5)). |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | % Rules are implicit relationships between objects /* rule_name(object1, object2, ...) :- fact/rule(object1, object2, ...) Suppose a clause is like : P :- Q;R. This can also be written as P :- Q. P :- R. If one clause is like : P :- Q,R;S,T,U. Is understood as P :- (Q,R);(S,T,U). Or can also be written as: P :- Q,R. P :- S,T,U. */ |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | % Lets add some rules to our database % Add the following 2 lines to test.pl and load via [test]. happy(X, Y) :- likes(X, Y). unhappy(X, Y) :- dislikes(X, Y). % Now we can ask some questions ?- happy(keith, java). % Is keith happy writing java, yes true. ?- unhappy(keith, java). % Is keith unhappy writing java, no false. ?- happy(keith, cobol). % Is keith happy writing cobol, no false. ?- happy(_, java). % Is anyone happy to write java, ues true. % Use of anonymous variable ?- happy(keith, _). % Is keith happy, yes true ; % multiple matches, ; to continue true ; % or . to end true ; true. |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | % Complex Relations % Classic Family Tree keith married to cat parents of Fred married to mary parents of andy jane married to jim parents of sarah male(keith). male(fred). male(andy). male(jim). female(cat). female(mary). female(jane). female(sarah). parent(keith, fred). parent(cat, fred). parent(fred, andy). parent(mary, andy). parent(fred, jane). parent(mary, jane). parent(jane, sarah). parent(jim, sarah). mother(X,Y):- parent(X,Y),female(X). father(X,Y):- parent(X,Y),male(X). haschild(X):- parent(X,_). sister(X,Y):- parent(Z,X),parent(Z,Y),female(X),X\==Y. brother(X,Y):-parent(Z,X),parent(Z,Y),male(X),X\==Y. grandparent(X,Y):-parent(X,Z),parent(Z,Y). grandmother(X,Z):-mother(X,Y),parent(Y,Z). grandfather(X,Z):-father(X,Y),parent(Y,Z). wife(X,Y):-parent(X,Z),parent(Y,Z),female(X),male(Y). uncle(X,Z):-brother(X,Y),parent(Y,Z). predecessor(X, Z) :- parent(X, Z). predecessor(X, Z) :- parent(X, Y),predecessor(Y, Z). |
1 2 3 4 | % Tracing Execution trace. // Turn Trace on notrace. // Turn Trace off |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | % Arithmetic Operators + % Addition - % Subtraction * % Multiplication / % Division ** % Power // % Integer Division mod % Modulus % Comparison Operators X = Y % succeeds if X and Y unify (match) in the Prolog sense X \= Y % succeeds if X and Y do not unify; i.e. if not (X = Y) T1 == T2 % succeeds if terms T1 and T2 are identical; e.g. names of variables have to be the same T1 \== % succeeds if terms T1 and T2 are not identical E1 =:= E2 % succeeds if values of expressions E1 and E2 are equal E1 =\= E2 % succeeds if values of expressions E1 and E2 are not equal E1 < E2 % succeeds if numeric value of expression E1 is < numeric value of E2 E1 =< E2 % succeeds if numeric value of expression E1 is ≤ numeric value of E2 E1 > E2 % succeeds if numeric value of expression E1 is > numeric value of E2 E1 >= E2 % succeeds if numeric value of expression E1 is ≥ numeric value of E2 T1 @< T2 % succeeds if T1 is alphabetically < T2 T1 @=< T2 % succeeds if T1 is alphabetically ≤ T2 T1 @> T2 % succeeds if T1 is alphabetically > T2 T1 @>= T2 % succeeds if T1 is alphabetically ≥ T2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | % Loops % Recursive Predicates count_to_10(10) :- write(10),nl. count_to_10(X) :- write(X),nl, Y is X + 1, count_to_10(Y) % between/3 ?- between(1, 3, L). L = 1 ; L = 2 ; L = 3. count_down(L, H) :- between(L, H, Y), Z is H - Y, write(Z), nl. |
1 2 3 4 5 6 7 8 9 10 11 12 13 | % Decision Making % If q(X,Y) :- X > Y,write('X is greater'). % If-Then-Else statement gt(X,Y) :- X >= Y,write('X is greater or equal'). gt(X,Y) :- X < Y,write('X is smaller'). % If-Elif-Else statement gte(X,Y) :- X > Y,write('X is greater'). gte(X,Y) :- X =:= Y,write('X and Y are same'). gte(X,Y) :- X < Y,write('X is smaller'). |
1 2 3 4 5 6 7 8 9 10 11 | parent(jhon,bob). parent(lili,bob). male(jhon). female(lili). % Conjunction Logic father(X,Y) :- parent(X,Y),male(X). mother(X,Y) :- parent(X,Y),female(X). % Disjunction Logic child_of(X,Y) :- father(X,Y);mother(X,Y). |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | % Lists % A list is a data structure that is either empty or consists of two parts: % a head and a tail. The tail itself has to be a list. [a, b, c] = [a | [b, c] ] [a, b, c] = [a, b | [c] ] [a, b, c] = [a, b, c | [ ] ] % Membership list_member(X,[X|_]). list_member(X,[_|TAIL]) :- list_member(X,TAIL). list_member(b,[a,b,c]). % true list_member(x,[a,b,c]). % false list_member([b,c],[a,b,c]]). % true % Length list_length([],0). list_length([_|TAIL],N) :- list_length(TAIL,N1), N is N1 + 1. list_length([], Len). % Len = 0 list_length([a, b, c], Len). % Len = 3. list_length([a, b, [x, y, z]], Len). % Len = 3. % Concatenation list_concat([],L,L). list_concat([X1|L1],L2,[X1|L3]) :- list_concat(L1,L2,L3). list_concat([1,2],[a,b,c],NewList). % NewList = [1, 2, a, b, c]. list_concat([],[a,b,c],NewList). % NewList = [a,b,c] list_concat([[1,2,3],[p,q,r]],[a,b,c],NewList). % NewList = [[1,2,3],[p,q,r],a,b,c] % Deletion list_delete(X, [X], []). list_delete(X,[X|L1], L1). list_delete(X, [Y|L2], [Y|L1]) :- list_delete(X,L2,L1). list_delete(a,[a,e,i,o,u],NewList). % NewList = [e,i,o,u] list_delete(a,[a],NewList). % NewList = [] % Appending % Use of the (!) symbol, that is known as cut. So when the first line is % executed successfully, then we cut it, so it will not execute the next operation list_append(A,T,T) :- list_member(A,T),!. list_append(A,T,[A|T]). list_append(a,[e,i,o,u],NewList). % NewList = [a,e,i,o,u] list_append(e,[e,i,o,u],NewList). % NewList = [e,i,o,u] | ?- list_append([a,b],[e,i,o,u],NewList). % NewList = [[a,b],e,i,o,u] % Append into list list_append(A,T,T) :- list_member(A,T),!. list_append(A,T,[A|T]). % Insert into list list_insert(X,L,R) :- list_delete(X,R,L). % All permutations list_perm([],[]). list_perm(L,[X|P]) :- list_delete(X,L,L1),list_perm(L1,P). % Reverse a list list_rev([],[]). list_rev([Head|Tail],Reversed) :- list_rev(Tail, RevTail),list_concat(RevTail, [Head],Reversed). % Shift a list list_shift([Head|Tail],Shifted) :- list_concat(Tail, [Head],Shifted). % Check list is ordered list_order([X]). % All possible subsets list_subset([],[]). list_subset([Head|Tail],[Head|Subset]) :- list_subset(Tail,Subset). list_subset([Head|Tail],Subset) :- list_subset(Tail,Subset). % Union list_union([X|Y],Z,W) :- list_member(X,Z),list_union(Y,Z,W). list_union([X|Y],Z,[X|W]) :- \+ list_member(X,Z), list_union(Y,Z,W). list_union([],Z,Z). % Intersection list_intersect([X|Y],Z,[X|W]) :- list_member(X,Z), list_intersect(Y,Z,W). list_intersect([X|Y],Z,W) :- \+ list_member(X,Z), list_intersect(Y,Z,W). list_intersect([],Z,[]). % Odd & Even Length list_even_len([]). list_even_len([Head|Tail]) :- list_odd_len(Tail). list_odd_len([_]). list_odd_len([Head|Tail]) :- list_even_len(Tail). % Divide list into 2 (roughly ) equal sizes list_divide([],[],[]). list_divide([X],[X],[]). list_divide([X,Y|Tail], [X|List1],[Y|List2]) :- list_divide(Tail,List1,List2). % Max element in list max_of_two(X,Y,X) :- X >= Y. max_of_two(X,Y,Y) :- X < Y. list_max_elem([X],X). list_max_elem([X,Y|Rest],Max) :- list_max_elem([Y|Rest],MaxRest), max_of_two(X,MaxRest,Max). % Sum elements list_sum([],0). list_sum([Head|Tail], Sum) :- list_sum(Tail,SumTemp), Sum is Head + SumTemp. |
1 | % Backtracking |
1 | % Input / Output |
Built in predicates
1 2 3 4 5 6 7 8 9 | var(X) % succeeds if X is currently an un-instantiated variable. novar(X) % succeeds if X is not a variable, or already instantiated atom(X) % is true if X currently stands for an atom number(X) % is true if X currently stands for a number integer(X) % is true if X currently stands for an integer float(X) % is true if X currently stands for a real number. atomic(X) % is true if X currently stands for a number or an atom. compound(X) % is true if X currently stands for a structure. ground(X) % succeeds if X does not contain any un-instantiated variables. |
Argument Indicators
++ | At call time, the argument must be ground, i.e., the argument may not contain any variables that are still unbound. |
+ | At call time, the argument must be instantiated to a term satisfying some (informal) type specification. The argument need not necessarily be ground. For example, the term [_] is a list, although its only member is the anonymous variable, which is always unbound (and thus nonground). |
– | Argument is an output argument. It may or may not be bound at call-time. |
— | At call time, the argument must be unbound. This is typically used by predicates that create‘something’ and return a handle to the created object, such as open/3, which creates a stream. |
? | At call time, the argument must be bound to a partial term (a term which may or may not be ground) satisfying some (informal) type specification. |
: | Argument is a meta-argument, for example a term that can be called as goal. The predicate is thus a meta-predicate. This flag implies + . |
@ | Argument will not be further instantiated than it is at call-time. Typically used for type tests. |
! | Argument contains a mutable structure that may be modified using setarg/3 or nb_setarg/3. |
Comparison & Unification
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | ?Term1 = ?Term2 % Unify Term1 with Term2. True if the unification succeeds. It acts as if defined by the following fact: @Term1 \= @Term2 % Equivalent to \+Term1 = Term2. @Term1 == @Term2 % True if Term1 is equivalent to Term2. A variable is only identical to a sharing variable. @Term1 \== @Term2 % Equivalent to \+Term1 == Term2. @Term1 @< @Term2 % True if Term1 is before Term2 in the standard order of terms. @Term1 @=< @Term2 % True if both terms are equal (==/2) or Term1 is before Term2 in the standard order of terms. @Term1 @> @Term2 % True if Term1 is after Term2 in the standard order of terms. @Term1 @>= @Term2 % True if both terms are equal (==/2) or Term1 is after Term2 in the standard order of terms. +Term1 =@= +Term2 % True if Term1 is a variant of (or structurally equivalent to) Term2. +Term1 \=@= +Term2. % Equivalent to ‘\+Term1 =@= Term2' compare(?Order, @Term1, @Term2) unify_with_occurs_check(+Term1, +Term2) subsumes_term(@Generic, @Specific) term_subsumer(+Special1, +Special2, -General) unifiable(@X, @Y, -Unifier) ?=(@Term1, @Term2) |
Control Predicates
1 2 3 4 5 6 7 8 9 10 11 | fail false true repeat ! :Goal1 , :Goal2 % Conjunction (and) :Goal1 ; :Goal2 % Disjunction (or) :Goal1 | :Goal2 :Condition -> :Action. % If-then/If Then Else :Condition *-> :Action ; :Else \+ :Goal |
Delimited Conditions
1 2 3 | reset(:Goal, ?Ball, -Continuation) shift(+Ball) shift_for_copy(+Ball) |
Editing
1 2 3 4 5 6 7 | edit(+Specification) edit prolog_edit:locate(+Spec, -FullSpec, -Location) prolog_edit:locate(+Spec, -Location) prolog_edit:edit_source(+Location) prolog_edit:edit_command(+Editor, -Command) prolog_edit:load |
Exception Handling
1 2 3 | catch(:Goal, +Catcher, :Recover) throw(+Exception) catch_with_backtrace(:Goal, +Catcher, :Recover) |
Meta Call Predicates
1 2 3 4 5 6 7 8 9 10 11 12 13 | call(:Goal) call(:Goal, +ExtraArg1, ...) apply(:Goal, +List) not(:Goal) once(:Goal) ignore(:Goal) call_with_depth_limit(:Goal, +Limit, -Result) call_with_inference_limit(:Goal, +Limit, -Result) setup_call_cleanup(:Setup, :Goal, :Cleanup) setup_call_catcher_cleanup(:Setup, :Goal, +Catcher, :Cleanup) call_cleanup(:Goal, :Cleanup) call_cleanup(:Goal, +Catcher, :Cleanup) undo(:Goal) |
Printing
1 2 3 4 5 6 7 8 9 10 | print_message(+Kind, +Term) print_message_lines(+Stream, +Prefix, +Lines) message_hook(+Term, +Kind, +Lines) thread_message_hook(+Term, +Kind, +Lines) message_property(+Kind, ?Property) prolog:message_line_element(+Stream, +Term) prolog:message_prefix_hook(+ContextTerm, -Prefix) message_to_string(+Term, -String) version version(+Message) |
Source Files
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | % Loading source files load_files(:Files) load_files(:Files, +Options) consult(:File) ensure_loaded(:File) include(+File) require(+Predicates) encoding(+Encoding) make library_directory(?Atom) file_search_path(+Alias, -Path) expand_file_search_path(+Spec, -Path) prolog_file_type(?Extension, ?Type) source_file(?File) source_file(:Pred, ?File) source_file_property(?File, ?Property) exists_source(+Source) exists_source(+Source, -File) unload_file(+File) prolog_load_context(?Key, ?Value) source_location(-File, -Line) at_halt(:Goal) cancel_halt(+Reason) initialization(:Goal) initialization(:Goal, +When) initialize compiling |
Verify Term
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var(@Term) nonvar(@Term) integer(@Term) float(@Term) rational(@Term) rational(@Term, -Numerator, -Denominator) number(@Term) atom(@Term) blob(@Term, ?Type) string(@Term) atomic(@Term) compound(@Term) callable(@Term) ground(@Term) cyclic_term(@Term) acyclic_term(@Term) |
Signals
1 2 3 | on_signal(+Signal, -Old, :New) current_signal(?Name, ?Id, ?Handler) prolog_alert_signal(?Old, +New) |
DCG Grammar Rules
1 2 3 | phrase(:DCGBody, ?List) phrase(:DCGBody, ?List, ?Rest) call_dcg(:DCGBody, ?State0, ?State) |
Database
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | abolish(:PredicateIndicator) abolish(+Name, +Arity) copy_predicate_clauses(:From, :To) redefine_system_predicate(+Head) retract(+Term) retractall(+Head) asserta(+Term) assertz(+Term) assert(+Term) asserta(+Term, -Reference) assertz(+Term, -Reference) assert(+Term, -Reference) transaction(:Goal) transaction(:Goal, +Options) transaction(:Goal, :Constraint, +Mutex) snapshot(:Goal) current_transaction(-Goal) transaction_updates(-Updates) recorda(+Key, +Term, -Reference) recorda(+Key, +Term) recordz(+Key, +Term, -Reference) recordz(+Key, +Term) recorded(?Key, ?Value, ?Reference) recorded(+Key, -Value) erase(+Reference) instance(+Reference, -Term) get_flag(+Key, -Value) set_flag(+Key, Value) flag(+Key, -Old, +New) trie_new(-Trie) trie_destroy(+Trie) is_trie(@Trie) current_trie(-Trie) trie_insert(+Trie, +Key) trie_insert(+Trie, +Key, +Value) trie_update(+Trie, +Key, +Value) trie_insert(+Trie, +Term, +Value, -Handle) trie_delete(+Trie, +Key, ?Value) trie_lookup(+Trie, +Key, -Value) trie_term(+Handle, -Term) trie_gen(+Trie, ?Key) trie_gen(+Trie, ?Key, -Value) trie_gen_compiled(+Trie, ?Key) trie_gen_compiled(+Trie, ?Key, -Value) trie_property(?Trie, ?Property) term_hash(+Term, -HashKey) term_hash(+Term, +Depth, +Range, -HashKey) variant_sha1(+Term, -SHA1) variant_hash(+Term, -HashKey) |
Predicate Properties
1 2 3 4 5 6 7 | dynamic :PredicateIndicator, ... dynamic(:ListOfPredicateIndicators, +Options) compile_predicates(:ListOfPredicateIndicators) multifile :PredicateIndicator, ... discontiguous :PredicateIndicator, ... public :PredicateIndicator, ... non_terminal :PredicateIndicator, ... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | % SWI Libraries library(aggregate). % Aggregation operators on backtrackable predicates library(ansi_term) % Print decorated text to ANSI consoles library(apply) % Apply predicates on a list library(assoc) % Association lists library(broadcast) % Broadcast and receive event notifications library(charsio) % I/O on Lists of Character Codes library(check) % Consistency checking library(clpb): CLP(B) % Constraint Logic Programming over Boolean Variables library(clpfd): CLP(FD). % Constraint Logic Programming over Finite Domains library(clpqr) % Constraint Logic Programming over Rationals and Reals library(csv) % Process CSV (Comma-Separated Values) data library(dcg/basics) % Various general DCG utilities library(dcg/high_order). % High order grammar operations library(debug) % Print debug messages and test assertions library(dicts) % Dict utilities library(error) % Error generating support library(fastrw) % Fast reading and writing of terms library(gensym) % Generate unique symbols library(heaps) % heaps/priority queues library(increval) % Incremental dynamic predicate modification library(intercept) % Intercept and signal interface library(iostream) % Utilities to deal with streams library(listing) % List programs and pretty print clauses library(lists) % List Manipulation library(main) % Provide entry point for scripts library(nb_set) % Non-backtrackable set library(www_browser) % Open a URL in the users browser library(occurs) % Finding and counting sub-terms library(option) % Option list processing library(optparse) % command line parsing library(ordsets) % Ordered set manipulation library(pairs) % Operations on key-value lists library(persistency). % Provide persistent dynamic predicates library(pio) % Pure I/O library(portray_text). % Portray text library(predicate_options) % Declare option-processing of predicates library(prolog_debug) % User level debugging tools library(prolog_jiti). % Just In Time Indexing (JITI) utilities library(prolog_trace). % Print access to predicates library(prolog_pack) % A package manager for Prolog library(prolog_xref) % Prolog cross-referencer data collection library(quasi_quotations). % Define Quasi Quotation syntax library(random) % Random numbers library(rbtrees) % Red black trees library(readutil). % Read utilities library(record). % Access named fields in a term library(registry) % Manipulating the Windows registry library(settings). % Setting management library(statistics) % Get information about resource usage library(strings) % String utilities library(simplex) % Solve linear programming problems library(solution_sequences). % Modify solution sequences library(tables) % XSB interface to tables library(terms) % Term manipulation library(thread) % High level thread primitives library(thread_pool) % Resource bounded thread management library(ugraphs) % Graph manipulation library library(url) % Analysing and constructing URL library(varnumbers) % Utilities for numbered terms library(yall) % Lambda expressions |