Path: news.eternal-september.org!eternal-september.org!feeder3.eternal-september.org!weretis.net!feeder8.news.weretis.net!reader5.news.weretis.net!news.solani.org!.POSTED!not-for-mail From: Mild Shock Newsgroups: comp.lang.prolog Subject: Higher Order Logic Programming and Autograd Date: Tue, 11 Mar 2025 13:02:47 +0100 Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Injection-Date: Tue, 11 Mar 2025 12:02:45 -0000 (UTC) Injection-Info: solani.org; logging-data="1424706"; mail-complaints-to="abuse@news.solani.org" User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0 SeaMonkey/2.53.20 Cancel-Lock: sha1:7GvTkx+ElKuwRDKBA7mlkwqgTeo= X-Mozilla-News-Host: news://news.solani.org:119 X-User-ID: eJwFwQEBBDEIAzBLMEr5yaH88C/hkgw6p8AkcnMbdk8T71nb5oDRR6Cs5Kz/0Esy7q3gQuHjR/exfq2WPkvwFak= Somehow I shied away from implementing call/n for my new Prolog system. I thought my new Prolog system has only monomorphic caches , I will never be able to replicate what I did for my old Prolog system with arity polymorphic caches. This changed when I had the idea to dynamically add a cache for the duration of a higher order loop such as maplist/n, foldl/n etc… So this is the new implementation of maplist/3: % maplist(+Closure, +List, -List) maplist(C, L, R) :- sys_callable_cacheable(C, D), sys_maplist(L, D, R). % sys_maplist(+List, +Closure, -List) sys_maplist([], _, []). sys_maplist([X|L], C, [Y|R]) :- call(C, X, Y), sys_maplist(L, C, R). Its similar as the SWI-Prolog implementation in that it reorders the arguments for better first argument indexing. But the new thing is sys_callable_cacheable/1, which prepares the closure to be more efficiently called. The invocation of the closure is already quite fast since call/3 is implemented natively, but the cache adds an itch more speed. Here some measurements that I did: /* SWI-Prolog 9.3.20 */ ?- findall(X,between(1,1000,X),L), time((between(1,1000,_), maplist(succ,L,_),fail; true)), fail. % 2,003,000 inferences, 0.078 CPU in 0.094 seconds /* Scryer Prolog 0.9.4-350 */ ?- findall(X,between(1,1000,X),L), time((between(1,1000,_), maplist(succ,L,_),fail; true)), fail. % CPU time: 0.318s, 3_007_105 inferences /* Dogelog Player 1.3.1 */ ?- findall(X,between(1,1000,X),L), time((between(1,1000,_), maplist(succ,L,_),fail; true)), fail. % Zeit 342 ms, GC 0 ms, Lips 11713646, Uhr 10.03.2025 09:18 /* realla Prolog 2.64.6-2 */ ?- findall(X,between(1,1000,X),L), time((between(1,1000,_), maplist(succ,L,_),fail; true)), fail. % Time elapsed 1.694s, 15004003 Inferences, 8.855 MLips Not surprisingly SWI-Prolog is fastest. What was a little surprise is that Scryer Prolog can do it quite fast, possibly since they heavily use maplist/n all over the place, they came up with things like '$fast_call' etc.. in their call/n implementation. Trealla Prolog is a little bit disappointing at the moment.