You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
BIG CAVEAT: This will especially fail with multiple inheritance, because I thought subtyping is the same as subclassing! But [[https://www.cmi.ac.in/~madhavan/courses/pl2009/lecturenotes/lecture-notes/node28.html][subtyping is different from subclassing]]. (Also [[https://www.cs.princeton.edu/courses/archive/fall98/cs441/mainus/node12.html][this]].)
@@ -13,31 +13,34 @@ The library primarily aims to provide a function type to dispatch on types rathe
13
13
14
14
Support for optional and keyword arguments, as well as heterogeneous lambda lists is also provided.
15
15
16
-
Load the asdf system =polymorphic-functions-lite= if you are happy with run-time dispatch. The system =polymorphic-functions= provides compile-time dispatch through the use of CLTL2 through [[https://github.com/alex-gutev/cl-environments][cl-environments]]. This takes place when the call-site is compiled with =(declare (optimize speed (debug 1)))= declaration in place. The newly added (= unstable) [[#specializing][specializing]]
16
+
Load the asdf system =polymorphic-functions-lite= if you are happy with run-time dispatch. The system =polymorphic-functions= provides optional compile-time dispatch through the use of CLTL2 through [[https://github.com/alex-gutev/cl-environments][cl-environments]]. See below for details. The newly added (= unstable) [[#specializing][specializing]]
17
17
macro also provides runtime numcl/julia-like JAOT dispatch analogous to [[https://github.com/numcl/specialized-function][specialized-function]].
18
18
19
19
Continuous Integration through Github Actions tests this library on SBCL, CCL, and ECL. The library was initially put to use at [[https://github.com/digikar99/numericals/][numericals]], but numericals has subsequently moved to the polymorphic-functions variant at [[https://gitlab.com/digikar/peltadot/][peltadot]]. This library continues to be used at [[https://github.com/lisp-polymorph/][lisp-polymorph]].
20
20
21
-
See the [[#limitations][pitfalls]] before using this library in a production environment!
21
+
See the [[#pitfalls-and-limitations][pitfalls]] before using this library in a production environment!
22
22
23
23
* Table of Contents
24
24
:PROPERTIES:
25
25
:TOC: :include all :ignore this :depth 4
26
26
:END:
27
27
28
28
:CONTENTS:
29
-
- [[#basic-usage][Basic Usage]]
29
+
- [[#introduction][Introduction]]
30
+
- [[#basic-usage][Basic Usage]]
30
31
- [[#installation][Installation]]
31
32
- [[#getting-it-from-ultralisp][Getting it from ultralisp]]
32
33
- [[#getting-it-from-clpm][Getting it from clpm]]
33
34
- [[#getting-it-using-download-dependencies][Getting it using download-dependencies]]
Finally quickload it to install other dependencies.
292
327
293
328
#+begin_src lisp
294
329
(ql:quickload "polymorphic-functions")
@@ -400,17 +435,164 @@ The arguments are ordered in the order they are specified in the case of require
400
435
:CUSTOM_ID: slimeswank-integration
401
436
:END:
402
437
403
-
At the moment, SLIME is non-extensible. There is an [[https://github.com/slime/slime/issues/642][open issue here]] about this. Until then, loading =(asdf:load-system "polymorphic-functions/swank")= and calling =(polymorphic-functions::extend-swank)= should get you going. This system essentially is just one file at file:src/swank.lisp.
438
+
At the moment, SLIME is non-extensible. There is an [[https://github.com/slime/slime/issues/642][open issue here]] about this. Until then, loading =(asdf:load-system "polymorphic-functions-lite/swank")= or =(asdf:load-system "polymorphic-functions/swank")= and calling =(polymorphic-functions::extend-swank)= should get you going. This system essentially is just one file at file:src/swank.lisp.
439
+
440
+
** Compiler Error Messages
441
+
:PROPERTIES:
442
+
:CUSTOM_ID: compiler-error-messages
443
+
:END:
444
+
445
+
It is a very valid concern to want good error messages from your compiler.
446
+
447
+
For polymorphic-functions-lite which performs only run time dispatch, the sole place compiler error messages arise is during the compilation of the polymorphs themselves. Polymorphic functions does not do any special compilation of the polymorph bodies beyond macroexpansion - the compilation is handled by the underlying lisp system itself. Thus, the goodness of compiler error messages is limited by the underlying lisp system. For example, consider compilation of the below code on SBCL 2.3.11:
448
+
449
+
#+begin_src lisp
450
+
(defpackage :pf-user
451
+
(:use :cl :polymorphic-functions))
452
+
453
+
(in-package :pf-user)
454
+
455
+
(defpolymorph my= ((a string) (b string))
456
+
boolean
457
+
(string= 2 a))
458
+
#+end_src
459
+
460
+
The error messages are generated very similar to a function defined using =cl:defun=:
Constant 2 conflicts with its asserted type (OR STRING SYMBOL CHARACTER).
487
+
See also:
488
+
SBCL Manual, Handling of Types [:node]
489
+
490
+
Compilation failed.
491
+
#+end_src
492
+
493
+
The case for the nonlite polymorphic-functions is more complex. The polymorphs themselves stay the same and will produce similar error messages as above. But another class of compiler error messages arise pertaining to the compilation of calls to these polymorphic-functions. To consider a slightly non-trivial case^, we will look into optimizing the compilation of a call to =numericals:mean= which compute the mean of the elements of a given array-like. =numericals:mean= is itself a polymorphic-function as you can check from the result of =(type-of (fdefinition 'numericals:mean))=. This, however, is implemented as a polymorphic-function over =numericals:sum=.
494
+
495
+
#+begin_src lisp
496
+
(uiop:define-package :numericals-user
497
+
(:mix :numericals :cl))
498
+
499
+
(in-package :numericals-user)
500
+
501
+
;; To focus on the compiler notes by polymorphic-functions,
502
+
;; instead of SBCL, we muffle SBCL's compiler notes.
Compiling the last form should emit a compiler note such as the following:
511
+
512
+
#+begin_src lisp
513
+
; processing (DEFUN GENERIC-MEAN ...)
514
+
; In file /tmp/slimePh90MB
515
+
; (Compiler) Macro of
516
+
; #<PELTADOT/POLYMORPHIC-FUNCTIONS:POLYMORPHIC-FUNCTION MEAN (8)>
517
+
; is unable to optimize
518
+
; (MEAN ARRAY-LIKE)
519
+
; because:
520
+
;
521
+
; Type of
522
+
; NUMERICALS.IMPL::OUT
523
+
; could not be determined
524
+
; Type of
525
+
; ARRAY-LIKE
526
+
; could not be determined
527
+
#+end_src
528
+
529
+
If you are using SLIME, you should also see the =(mean array-like)= form underlined to indicate that it was this form that emitted this compiler note. This should also be evident from the compiler note emitted above. This compiler note says that the type of =array-like= could not be derived.
530
+
Let us try supplying a more specific argument.
531
+
532
+
#+begin_src lisp
533
+
(defun single-float-mean (array)
534
+
(declare (optimize speed)
535
+
(type (simple-array single-float) array))
536
+
(mean array))
537
+
#+end_src
538
+
539
+
This compiled without emitting any notes! If you compare =(disassemble 'generic-mean)= with =(disassemble 'single-float-mean)=, you will find that the latter contains a call to the CFFI function BMAS_ssum^^ while the former is simply calls the =numericals:mean= function. Let us check if this makes any performance difference!
540
+
541
+
#+begin_src lisp
542
+
(let ((a (rand 1000 1000 :type 'single-float)))
543
+
(time (loop repeat 1000 do (generic-mean a))))
544
+
;; Evaluation took:
545
+
;; 0.636 seconds of real time
546
+
;; 0.636028 seconds of total run time (0.636028 user, 0.000000 system)
547
+
;; 100.00% CPU
548
+
;; 1,404,383,458 processor cycles
549
+
;; 0 bytes consed
550
+
(let ((a (rand 1000 1000 :type 'single-float)))
551
+
(time (loop repeat 1000 do (single-float-mean a))))
552
+
;; Evaluation took:
553
+
;; 0.632 seconds of real time
554
+
;; 0.632850 seconds of total run time (0.632850 user, 0.000000 system)
555
+
;; 100.16% CPU
556
+
;; 1,397,359,136 processor cycles
557
+
;; 0 bytes consed
558
+
#+end_src
559
+
560
+
For a single-float array of size 1000x1000, this made no performance difference. This makes sense, because for such a large array, we expect most of the time to be spent within the C function BMAS_ssum itself and very overhead would be involved in the 1000 function calls. But what about for smaller arrays and greater number of high level function calls?
561
+
562
+
#+begin_src lisp
563
+
(let ((a (rand 100 :type 'single-float)))
564
+
(time (loop repeat 10000000 do (generic-mean a))))
565
+
;; Evaluation took:
566
+
;; 4.201 seconds of real time
567
+
;; 4.199076 seconds of total run time (3.883141 user, 0.315935 system)
568
+
;; [ Real times consist of 0.500 seconds GC time, and 3.701 seconds non-GC time. ]
569
+
;; [ Run times consist of 0.500 seconds GC time, and 3.700 seconds non-GC time. ]
570
+
;; 99.95% CPU
571
+
;; 9,269,228,604 processor cycles
572
+
;; 160,052,784 bytes consed
573
+
(let ((a (rand 100 :type 'single-float)))
574
+
(time (loop repeat 10000000 do (single-float-mean a))))
575
+
;; Evaluation took:
576
+
;; 0.920 seconds of real time
577
+
;; 0.918671 seconds of total run time (0.918671 user, 0.000000 system)
578
+
;; 99.89% CPU
579
+
;; 2,028,490,598 processor cycles
580
+
;; 0 bytes consed
581
+
#+end_src
582
+
583
+
Here, for arrays of size 100, this results in a performance difference of about 4 times! If or not this is relevant depends on your use case.
584
+
585
+
^: =numericals:mean= actually uses peltadot instead of polymorphic-functions, but the concepts are similar.
586
+
587
+
^^: =BMAS_ssum= uses SIMD under the hood. Because it is a C function, you can use it wherever you can use CFFI!
588
+
589
+
PS: Thanks to [[https://www.reddit.com/r/lisp/comments/1bq44p6/comment/kx4c0x8/?utm_source=share&utm_medium=web2x&context=3][u/corbasai on reddit]] for the motivation for this section!
404
590
405
591
** Pitfalls and Limitations
406
592
:PROPERTIES:
407
593
:CUSTOM_ID: pitfalls-and-limitations
408
594
:END:
409
595
410
-
:PROPERTIES:
411
-
:CUSTOM_ID: limitations
412
-
:END:
413
-
414
596
Yes, there are quite a few:
415
597
416
598
- *Integration with SLIME* currently works only on SBCL.
@@ -1087,4 +1269,3 @@ them.
1087
1269
1088
1270
Remove the [[#polymorph][polymorph]] associated with =name= with
0 commit comments