diff options
author | EuAndreh <eu@euandre.org> | 2025-03-31 21:51:40 -0300 |
---|---|---|
committer | EuAndreh <eu@euandre.org> | 2025-03-31 21:51:40 -0300 |
commit | 570ec471d1605318aeefb030cd78682ae442235b (patch) | |
tree | 51e17eabe37c6689f8799b55e6875c3480329a2c /src/content/tils/2021/04/24 | |
parent | Makefile, mkdeps.sh: Derive index.html and feed.xml from more static "sortdat... (diff) | |
download | euandre.org-570ec471d1605318aeefb030cd78682ae442235b.tar.gz euandre.org-570ec471d1605318aeefb030cd78682ae442235b.tar.xz |
src/content/: Update all files left to asciidoc
Diffstat (limited to 'src/content/tils/2021/04/24')
-rw-r--r-- | src/content/tils/2021/04/24/cl-generic-precedence.adoc | 98 | ||||
-rw-r--r-- | src/content/tils/2021/04/24/clojure-autocurry.adoc | 66 | ||||
-rw-r--r-- | src/content/tils/2021/04/24/scm-nif.adoc | 53 |
3 files changed, 111 insertions, 106 deletions
diff --git a/src/content/tils/2021/04/24/cl-generic-precedence.adoc b/src/content/tils/2021/04/24/cl-generic-precedence.adoc index 8051232..541afb0 100644 --- a/src/content/tils/2021/04/24/cl-generic-precedence.adoc +++ b/src/content/tils/2021/04/24/cl-generic-precedence.adoc @@ -1,20 +1,10 @@ ---- += Common Lisp argument precedence order parameterization of a generic function -title: Common Lisp argument precedence order parameterization of a generic function +When CLOS dispatches a method, it picks the most specific method definition to +the argument list: -date: 2021-04-24 2 - -layout: post - -lang: en - -ref: common-lisp-argument-precedence-order-parameterization-of-a-generic-function - ---- - -When CLOS dispatches a method, it picks the most specific method definition to the argument list: - -```lisp +[source,lisp] +---- * (defgeneric a-fn (x)) #<STANDARD-GENERIC-FUNCTION A-FN (0) {5815ACB9}> @@ -39,11 +29,13 @@ When CLOS dispatches a method, it picks the most specific method definition to t * (a-fn 1) :NUMBER-1 -``` +---- -CLOS uses a similar logic when choosing the method from parent classes, when multiple ones are available: +CLOS uses a similar logic when choosing the method from parent classes, when +multiple ones are available: -```lisp +[source,lisp] +---- * (defclass class-a () ()) #<STANDARD-CLASS CLASS-A {583E0B25}> @@ -63,11 +55,13 @@ CLOS uses a similar logic when choosing the method from parent classes, when mul ; Compiling Top-Level Form: #<STANDARD-METHOD ANOTHER-FN (CLASS-B) {584B8895}> -``` +---- -Given the above definitions, when inheriting from `class-a` and `class-b`, the order of inheritance matters: +Given the above definitions, when inheriting from `class-a` and `class-b`, the +order of inheritance matters: -```lisp +[source,lisp] +---- * (defclass class-a-coming-first (class-a class-b) ()) #<STANDARD-CLASS CLASS-A-COMING-FIRST {584BE6AD}> @@ -79,11 +73,14 @@ Given the above definitions, when inheriting from `class-a` and `class-b`, the o * (another-fn (make-instance 'class-b-coming-first)) :CLASS-B -``` +---- -Combining the order of inheritance with generic functions with multiple arguments, CLOS has to make a choice of how to pick a method given two competing definitions, and its default strategy is prioritizing from left to right: +Combining the order of inheritance with generic functions with multiple +arguments, CLOS has to make a choice of how to pick a method given two competing +definitions, and its default strategy is prioritizing from left to right: -```lisp +[source,lisp] +---- * (defgeneric yet-another-fn (obj1 obj2)) #<STANDARD-GENERIC-FUNCTION YET-ANOTHER-FN (0) {584D9EC9}> @@ -95,43 +92,58 @@ Combining the order of inheritance with generic functions with multiple argument * (yet-another-fn (make-instance 'class-a) (make-instance 'class-b)) :FIRST-ARG-SPECIALIZED -``` +---- -CLOS has to make a choice between the first and the second definition of `yet-another-fn`, but its choice is just a heuristic. -What if we want the choice to be based on the second argument, instead of the first? +CLOS has to make a choice between the first and the second definition of +`yet-another-fn`, but its choice is just a heuristic. What if we want the +choice to be based on the second argument, instead of the first? -For that, we use the `:argument-precedence-order` option when declaring a generic function: +For that, we use the `:argument-precedence-order` option when declaring a +generic function: -```lisp +[source,lisp] +---- * (defgeneric yet-another-fn (obj1 obj2) (:argument-precedence-order obj2 obj1)) #<STANDARD-GENERIC-FUNCTION YET-ANOTHER-FN (2) {584D9EC9}> * (yet-another-fn (make-instance 'class-a) (make-instance 'class-b)) :SECOND-ARG-SPECIALIZED -``` +---- -I liked that the `:argument-precedence-order` option exists. -We shouldn't have to change the arguments from `(obj1 obj2)` to `(obj2 obj1)` just to make CLOS pick the method that we want. -We can configure its default behaviour if desired, and keep the order of arguments however it best fits the generic function. +I liked that the `:argument-precedence-order` option exists. We shouldn't have +to change the arguments from `(obj1 obj2)` to `(obj2 obj1)` just to make CLOS +pick the method that we want. We can configure its default behaviour if +desired, and keep the order of arguments however it best fits the generic +function. -## Comparison with Clojure +== Comparison with Clojure Clojure has an equivalent, when using `defmulti`. -Since when declaring a multi-method with `defmulti` we must define the dispatch function, Clojure uses it to pick the method definition. -Since the dispatch function is required, there is no need for a default behaviour, such as left-to-right. +Since when declaring a multi-method with `defmulti` we must define the dispatch +function, Clojure uses it to pick the method definition. Since the dispatch +function is required, there is no need for a default behaviour, such as +left-to-right. -## Conclusion +== Conclusion -Making the argument precedence order configurable for generic functions but not for class definitions makes a lot of sense. +Making the argument precedence order configurable for generic functions but not +for class definitions makes a lot of sense. -When declaring a class, we can choose the precedence order, and that is about it. -But when defining a generic function, the order of arguments is more important to the function semantics, and the argument precedence being left-to-right is just the default behaviour. +When declaring a class, we can choose the precedence order, and that is about +it. But when defining a generic function, the order of arguments is more +important to the function semantics, and the argument precedence being +left-to-right is just the default behaviour. -One shouldn't change the order of arguments of a generic function for the sake of tailoring it to the CLOS priority ranking algorithm, but doing it for a class definition is just fine. +One shouldn't change the order of arguments of a generic function for the sake +of tailoring it to the CLOS priority ranking algorithm, but doing it for a class +definition is just fine. TIL. -## References +== References + +:clos-wiki: https://en.wikipedia.org/wiki/Object-Oriented_Programming_in_Common_Lisp -1. [Object-Oriented Programming in Common Lisp: A Programmer's Guide to CLOS](https://en.wikipedia.org/wiki/Object-Oriented_Programming_in_Common_Lisp), by Sonja E. Keene +. {clos-wiki}[Object-Oriented Programming in Common Lisp: A Programmer's Guide + to CLOS], by Sonja E. Keene diff --git a/src/content/tils/2021/04/24/clojure-autocurry.adoc b/src/content/tils/2021/04/24/clojure-autocurry.adoc index c1e277f..d7dd557 100644 --- a/src/content/tils/2021/04/24/clojure-autocurry.adoc +++ b/src/content/tils/2021/04/24/clojure-autocurry.adoc @@ -1,22 +1,13 @@ ---- += Clojure auto curry -title: Clojure auto curry +:defcurry-orig: https://lorettahe.github.io/clojure/2016/09/22/clojure-auto-curry -date: 2021-04-24 1 +Here's a simple macro defined by {defcurry-orig}[Loretta He] to create Clojure +functions that are curried on all arguments, relying on Clojure's multi-arity +support: -updated_at: 2021-04-27 - -layout: post - -lang: en - -ref: clojure-auto-curry - ---- - -Here's a simple macro defined by [Loretta He][lorettahe] to create Clojure functions that are curried on all arguments, relying on Clojure's multi-arity support: - -```clojure +[source,clojure] +---- (defmacro defcurry [name args & body] (let [partials (map (fn [n] @@ -25,11 +16,12 @@ Here's a simple macro defined by [Loretta He][lorettahe] to create Clojure funct `(defn ~name (~args ~@body) ~@partials))) -``` +---- A naive `add` definition, alongside its usage and macroexpansion: -```clojure +[source,clojure] +---- user=> (defcurry add [a b c d e] (+ 1 2 3 4 5)) @@ -64,22 +56,24 @@ user=> (pprint ([a b c] (clojure.core/partial add a b c)) ([a b c d] (clojure.core/partial add a b c d)))) nil -``` +---- -This simplistic `defcurry` definition doesn't support optional parameters, multi-arity, `&` rest arguments, docstrings, etc., but it could certainly evolve to do so. +This simplistic `defcurry` definition doesn't support optional parameters, +multi-arity, `&` rest arguments, docstrings, etc., but it could certainly evolve +to do so. -I like how `defcurry` is so short, and abdicates the responsability of doing the multi-arity logic to Clojure's built-in multi-arity support. -Simple and elegant. +I like how `defcurry` is so short, and abdicates the responsability of doing the +multi-arity logic to Clojure's built-in multi-arity support. Simple and +elegant. Same Clojure as before, now with auto-currying via macros. -[lorettahe]: http://lorettahe.github.io/clojure/2016/09/22/clojure-auto-curry - -## Comparison with Common Lisp +== Comparison with Common Lisp My attempt at writing an equivalent for Common Lisp gives me: -```lisp +[source,lisp] +---- (defun partial (fn &rest args) (lambda (&rest args2) (apply fn (append args args2)))) @@ -96,15 +90,17 @@ My attempt at writing an equivalent for Common Lisp gives me: (let ((func (lambda ,args ,@body))) (curry-n (- ,(length args) (length rest)) (apply #'partial func rest))))) -``` +---- -Without built-in multi-arity support, we have to do more work, like tracking the number of arguments consumed so far. -We also have to write `#'partial` ourselves. -That is, without dependending on any library, sticking to ANSI Common Lisp. +Without built-in multi-arity support, we have to do more work, like tracking the +number of arguments consumed so far. We also have to write `#'partial` +ourselves. That is, without dependending on any library, sticking to ANSI +Common Lisp. The usage is pretty similar: -```lisp +[source,lisp] +---- * (defcurry add (a b c d e) (+ a b c d e)) ADD @@ -128,8 +124,10 @@ ADD (LET ((FUNC (LAMBDA (A B C D E) (+ A B C D E)))) (CURRY-N (- 5 (LENGTH REST)) (APPLY #'PARTIAL FUNC REST)))) T -``` +---- -This also require `funcall`s, since we return a `lambda` that doesn't live in the function namespace. +This also require `funcall`s, since we return a `lambda` that doesn't live in +the function namespace. -Like the Clojure one, it doesn't support optional parameters, `&rest` rest arguments, docstrings, etc., but it also could evolve to do so. +Like the Clojure one, it doesn't support optional parameters, `&rest` rest +arguments, docstrings, etc., but it also could evolve to do so. diff --git a/src/content/tils/2021/04/24/scm-nif.adoc b/src/content/tils/2021/04/24/scm-nif.adoc index f53451b..f70e533 100644 --- a/src/content/tils/2021/04/24/scm-nif.adoc +++ b/src/content/tils/2021/04/24/scm-nif.adoc @@ -1,35 +1,28 @@ ---- += Three-way conditional for number signs on Lisp -title: Three-way conditional for number signs on Lisp +:on-lisp: https://www.paulgraham.com/onlisptext.html +:sicp: https://mitpress.mit.edu/sites/default/files/sicp/index.html -date: 2021-04-24 3 +A useful macro from Paul Graham's {on-lisp}[On Lisp] book: -updated_at: 2021-08-14 - -layout: post - -lang: en - -ref: three-way-conditional-for-number-signs-on-lisp - ---- - -A useful macro from Paul Graham's [On Lisp][on-lisp] book: - -```lisp +[source,lisp] +---- (defmacro nif (expr pos zero neg) (let ((g (gensym))) `(let ((,g ,expr)) (cond ((plusp ,g) ,pos) ((zerop ,g) ,zero) (t ,neg))))) -``` +---- -After I looked at this macro, I started seeing opportunities to using it in many places, and yet I didn't see anyone else using it. +After I looked at this macro, I started seeing opportunities to using it in many +places, and yet I didn't see anyone else using it. -The latest example I can think of is section 1.3.3 of [Structure and Interpretation of Computer Programs][sicp], which I was reading recently: +The latest example I can think of is section 1.3.3 of {sicp}[Structure and +Interpretation of Computer Programs], which I was reading recently: -```scheme +[source,scheme] +---- (define (search f neg-point pos-point) (let ((midpoint (average neg-point pos-point))) (if (close-enough? neg-point post-point) @@ -40,11 +33,14 @@ The latest example I can think of is section 1.3.3 of [Structure and Interpretat ((negative? test-value) (search f midpoint pos-point)) (else midpoint)))))) -``` +---- -Not that the book should introduce such macro this early, but I couldn't avoid feeling bothered by not using the `nif` macro, which could even remove the need for the intermediate `test-value` variable: +Not that the book should introduce such macro this early, but I couldn't avoid +feeling bothered by not using the `nif` macro, which could even remove the need +for the intermediate `test-value` variable: -```scheme +[source,scheme] +---- (define (search f neg-point pos-point) (let ((midpoint (average neg-point pos-point))) (if (close-enough? neg-point post-point) @@ -53,11 +49,10 @@ Not that the book should introduce such macro this early, but I couldn't avoid f (search f neg-point midpoint) (midpoint) (search f midpoint pos-point))))) -``` - -It also avoids `cond`'s extra clunky parentheses for grouping, which is unnecessary but built-in. +---- -As a macro, I personally feel it tilts the balance towards expressivenes despite its extra cognitive load toll. +It also avoids `cond`'s extra clunky parentheses for grouping, which is +unnecessary but built-in. -[on-lisp]: http://www.paulgraham.com/onlisptext.html -[sicp]: https://mitpress.mit.edu/sites/default/files/sicp/index.html +As a macro, I personally feel it tilts the balance towards expressivenes despite +its extra cognitive load toll. |