Replies: 2 comments 2 replies
-
Wait, producing a series of commands might be more valuable than I thought, especially in Prolog. Am I right in thinking that: [ticket_ok(Runner),
initialize_metrics(Runner),
pull_latest_version(Runner)
unittests_ok(Runner),
build_artifacts_ok(Runner),
acceptance_tests_ok(Runner),
update_vcs_ok(Runner),
finalize_metrics(Runner),
results(Runner, Output)] (or something like it) would be a great target for a MI (metainterpreter) to consume? Is it "valid" to abuse an MI by making IT do the dirty work of the side-effects? Am I just shifting the complexity burden of the testing to testing the impure MI? 🤔 |
Beta Was this translation helpful? Give feedback.
-
I had similar situation in the past, I wanted to mock I/O for tests. Maybe it doesn't solve exactly your problem, but let me share it nevertheless. The idea is to run your program in a "world" where I/O predicates don't produce any side-effects. I got inspiration from Linear Logic which have very nice declarative reading. Here is the code: :- initialization(main).
:- dynamic([out/1]).
main :- callenv(useful, example).
test :- callenv(useless, example).
example :-
complex_predicate(P),
out(P).
complex_predicate(P) :- P = "Hello world!".
callenv(useless, G) :-
setup_call_cleanup(asserta(out(_)), G, retract(out(_))).
callenv(usefull, G) :-
setup_call_cleanup(asserta((out(A) :- write(A))), G, retract((out(_):-_))). Your main program resides in P.S. You can read about algebraic effects, but I find it an overkill for my use-case. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Let me give 3 examples:
Regarding the build pipeline, it could look something like:
where
Runner
might be a module or perhaps just a symbol, depending on how the others were defined.Now, all of these task predicates are heavily side-effecty. This is quite annoying, because it makes testing very difficult. And that is annoying because it makes testing-based design difficult. i.e., how do I write:
Simply mocking out the runner is... ok, but thing is that the output of
format_//2
is actually useful. So it can be used for verification and it actually does the job.It would be tempting to think that the output of
run_build_pipeline/2
might product a series of commands? Part of me feels like that's not really solving the problem, it's just adding more indirection to the problem. Because why not just haverun_build_pipeline/2
produceat that point, have I really saved myself anything?
Likewise with declarative timestamps and declarative UUIDs, it seems like "creating a command" doesn't really save much here. But if feels close to the right answer.
Somehow
library(pio)
andformat_//2
do a nice job of converting normally side-effecting work into terms that can be reasoned about, but the generalization of this technique escapes me.Beta Was this translation helpful? Give feedback.
All reactions