From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: Re: Is there a function for auto currying in Elisp? Date: Fri, 22 Dec 2017 08:51:21 -0500 Message-ID: References: <87tvwki1oe.fsf@petton.fr> <87efnnm8eg.fsf@petton.fr> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: blaine.gmane.org 1513950975 24388 195.159.176.226 (22 Dec 2017 13:56:15 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Fri, 22 Dec 2017 13:56:15 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux) Cc: emacs-devel@gnu.org To: Nicolas Petton Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Fri Dec 22 14:56:11 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eSNo2-0005zf-R3 for ged-emacs-devel@m.gmane.org; Fri, 22 Dec 2017 14:56:10 +0100 Original-Received: from localhost ([::1]:51462 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eSNq1-0007PX-B3 for ged-emacs-devel@m.gmane.org; Fri, 22 Dec 2017 08:58:13 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:50425) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eSNjR-0002DW-Iw for emacs-devel@gnu.org; Fri, 22 Dec 2017 08:51:26 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eSNjO-0006S4-EC for emacs-devel@gnu.org; Fri, 22 Dec 2017 08:51:25 -0500 Original-Received: from pmta21.teksavvy.com ([76.10.157.36]:34911) by eggs.gnu.org with esmtps (TLS1.0:RSA_ARCFOUR_SHA1:16) (Exim 4.71) (envelope-from ) id 1eSNjO-0006RI-8i for emacs-devel@gnu.org; Fri, 22 Dec 2017 08:51:22 -0500 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A2E6SgBPDT1a/3KZSC1dHQEBBQELAYM+g?= =?us-ascii?q?VqDbIVchHqPK4IBmT2Be4NKAoROQxQBAQEBAQEBAQEDaCiFJQEEASdSEAsNJxI?= =?us-ascii?q?UGDGKOQinDTohAoowAQEIAiaEDIIShV+BDosaBZMxkBiLJpYQKIdLmDo2I4FPM?= =?us-ascii?q?hoIMD2CKoR0I4psAQEB?= X-IPAS-Result: =?us-ascii?q?A2E6SgBPDT1a/3KZSC1dHQEBBQELAYM+gVqDbIVchHqPK4I?= =?us-ascii?q?BmT2Be4NKAoROQxQBAQEBAQEBAQEDaCiFJQEEASdSEAsNJxIUGDGKOQinDTohA?= =?us-ascii?q?oowAQEIAiaEDIIShV+BDosaBZMxkBiLJpYQKIdLmDo2I4FPMhoIMD2CKoR0I4p?= =?us-ascii?q?sAQEB?= X-IronPort-AV: E=Sophos;i="5.45,441,1508817600"; d="scan'208";a="14855920" Original-Received: from unknown (HELO pastel.home) ([45.72.153.114]) by smtp.teksavvy.com with ESMTP; 22 Dec 2017 08:51:21 -0500 Original-Received: by pastel.home (Postfix, from userid 20848) id 0564361626; Fri, 22 Dec 2017 08:51:21 -0500 (EST) In-Reply-To: <87efnnm8eg.fsf@petton.fr> (Nicolas Petton's message of "Fri, 22 Dec 2017 10:14:31 +0100") X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 76.10.157.36 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:221335 Archived-At: >> Of course, we can do the easy cases: >> >> (defun curry (f n) >> (if (< n 2) >> f >> (lambda (x) >> (curry (apply-partially f x) (- n 1))))) > That's exactly the implementation I was playing with yesterday :-) >> but ... I'm not sure we want to encourage this. > Why not? It's using a part of Elisp's implementation which is definitely not very efficient. If you're serious about using such a construct, you'd first want to make it into a macro so it avoids the use of apply-partially which just adds insult to injury. >> What's your use case(s)? > I don't have a specific use case right now, but I think that currying > can be very expressive and elegant, and fits extremely well with > functional programming, which Elisp is very capable of. "Real" functional programming tends to use lots of small functions, so it's important to optimize the implementation of function calls and closure creations. Elisp is not great at either of those: - E.g. creating a closure with N free variables, in a straightforward implementation typically requires one allocation of an object of size N+1 words or so. In Elisp, it requires allocation one 2 objects, one of size 6 (the `compiled-function`) and another of size N+M where M is the number of constants that appears within the function (and is typically larger than N). - The above definition of `curry` eats a fair chunk of stack when you finally call the function: for a given N you end up with N nestings of `apply-partially`, each one eating some stack space. If you use this heavily you're likely to want to bump the max stack depth. - Of course, each nesting of `apply-partially` involves apply+&rest, hence conversion list<->vector which means allocation of `cons` cells (luckily those "vectors" are stack allocated so they cost a bit less). - And of course, our implementation of function calls itself is not super efficient (several nested C function calls for each Elisp funcall, plus copying of arguments between different stacks), and all those lambda layerings exercise this weak spot of the language. The Elisp style is evolving and those inefficiencies are more often visible (e.g. cl-print's main bottleneck is the cost of apply+&rest in my tests), so we can hope that someone will work on reducing them at some point; and in general I do recommend to make your code clean and correct first and foremost. But keep in mind that Elisp's support for functional programming is a bit lacking in efficiency. Stefan