A short comment here. Erlang was developed using Prolog so the first versions were in Prolog. Originally then, it was more of a logic language but we decided, amongst many other things, that we didn’t want logical variables or back-tracking in the language so it became functional. Having the language implemented in Prolog made it easy to work with when the language evolved and became Erlang. When our original group wanted/required a much faster implementation, about 70x times faster, we moved away from interpreting it in Prolog and developed the first VM, the JAM, and moved everything from Prolog to Erlang.
Strand is a nice concurrent logic language and we did a serious experiment of using it to implement Erlang. We found that it was too logical and in some ways too concurrent/parallel so it was not a good base for Erlang. E.g. in Strand everything is done in parallel so we had to put effort into making the functional part sequential. You need to get it just the right amount of concurrency to be what you want.
In Strand with a clause like:
foo(X, Y) :- is_right(X), !, a(Y), b(Y), c(Y), d(Y), exit(die).
then a(), b(), c(), d() and exit() are all run into parallel so it will die way to fast.
Another concurrent logic language was Parlog from Imperial College Londong which IIRC you could explicitly serialise the clause body. I did an implementation of Parlog to both experiment with the language and to experiment with implementing a VM. It was fun and it worked and did exactly what it was supposed to do.