🧠 Logic: ⛓️ `foldl/4` predicate
📝 Purpose
Implement the foldl/4 Prolog predicate. This predicate performs a fold (left-fold) over a list, applying a goal to each element in the list, starting with an initial accumulator value and producing a final value after all elements are processed.
Rationale
This predicate is quite common and can facilitate the expression of certain governance rules, especially in scenarios where an aggregate decision or value must be derived from a list of inputs by applying a consistent operation across them...
🧪 Expected behavior
foldl/4 folds a list head-to-tail (“fold-left”), applying each element to the specified Goal. V0 serves as the initial accumulator value, and V is the final result of the folding operation.
foldl(:Goal, +List, +V0, -V)
Where:
Goal: A predicate that is applied to the elements of List and the accumulator. It should accept three arguments: an element of List, the current accumulator, and the new accumulator.List: A list of elements to be folded over.V0: The initial accumulator value.V: The final value of the accumulator after folding the entire list.
🎯 Example
?- foldl(plus, [1, 2, 3, 4], 0, Result).
Result = 10.
?- foldl(atomic_list_concat, ['hello', ' ', 'world'], '', Result).
Result = 'hello world'.
✅ Acceptance Criteria
- [ ] The predicate is implemented according to the described behavior and examples
- [ ] The predicate passes all test cases
- [ ] Documentation is updated accordingly.
🔗 References and linked predicate
That's an important I agree.
I also think it is easier to implement it in Prolog directly than as a custom Go predicate:
foldl(Goal, [H|T], Result) :-
foldl(Goal, T, H, Result).
foldl(Goal, [H|T], Acc, Result) :-
call(Goal, Acc, H, NewAcc),
foldl(Goal, T, NewAcc, Result).
foldl(_Goal, [], Result, Result).
I'd like to propose to allow implementing new predicates directly in prolog, which would be added to the bootstrap.pl when loading the VM.
I recall for example that we've implemented the source_files/1 predicate this way, but I'm not comfortable editing the bootstrapping program directly as we don't benefit from autogenerated documentation, tests, etc.. I'd like instead to propose an alternative way of registering predicates by providing its related Prolog code the registry would load after the bootstrap program.
What do you think @ccamel ? We may lose in performance though, maybe some benchmarks could help us on that
Hey! I agree. IMHO, native predicate implementations should be reserved for:
- Predicates that need to interact with the environment/system.
- Predicates where the Prolog implementation complexity makes a native approach preferable.
Regarding foldl/n, you're right, this is a typical predicate that can be implemented in pure Prolog. And that's exactly what swi-prolog does, afais: implemented it in apply.pl as follows:
foldl(Goal, List, V0, V) :-
foldl_(List, Goal, V0, V).
foldl_([], _, V, V).
foldl_([H|T], Goal, V0, V) :-
call(Goal, H, V0, V1),
foldl_(T, Goal, V1, V).
Further considerations.
- Prolog source organization:
- The bootstrap should serve only as a minimalist foundation for VM execution (for now)
- Better approach: Split into modules, similar to existing Go files (1 file = one module, but we could consider to have 1 pkg = one module)
- Each module would contain:
- Native predicates in Go
- Source predicates in Prolog
- Like native predicates, source predicates will need to be compiled and executed in the VM
Note: bootstrap.pl will be deprecated once module implementation is available in ichiban/prolog (see PR https://github.com/ichiban/prolog/pull/307), and we can leverage it to treat our modules as first-class Prolog citizens, enabling dynamic module loading at runtime and proper module scoping and visibility rules...
- Documentation:
- The current documentation generator needs to be extended to extract predicate descriptions directly from prolog source files. This should be a relatively straightforward enhancement, I believe.
- Performance considerations:
- As you mentioned, benchmarking would be great to have.
- Potential optimization: Implement bytecode caching for compiled predicates.
If you want to move forward on these topics, we should create tickets to address the different steps. Also, some topics need to be addressed in axone-protocol/prolog.
Hi, Christope, sorry for leaving comment here without your agreement and respecting the team rule. Because I wanna contribute to Axone team's development and join your team, so I am going to solve issues. So could you give me some issue to be solved quickly as test task?
@solthereum please contact us on our discord server.
thanks @ccamel, I left message to you.