axone-protocol / axoned

⛓️ Axone blockchain 💫
https://axone.xyz
Apache License 2.0
162 stars 123 forks source link

🧠 Logic: ⛓️ `foldl/4` predicate #788

Open ccamel opened 5 days ago

ccamel commented 5 days ago

📝 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:

🎯 Example

?- foldl(plus, [1, 2, 3, 4], 0, Result).
Result = 10.

?- foldl(atomic_list_concat, ['hello', ' ', 'world'], '', Result).
Result = 'hello world'.

✅ Acceptance Criteria

🔗 References and linked predicate

amimart commented 4 days ago

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

ccamel commented 3 days ago

Hey! I agree. IMHO, native predicate implementations should be reserved for:

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.

  1. 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...

  1. 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.
  2. Performance considerations:

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.