# brev-separate This is `brev-separate`, a miscellaneous hodge-podge of macros and procedures that all have the shared aim of brevity. Sort of my take on the `clojurian` and `miscmacros` and `(chicken base)` genre. It's called `brev-separate` since the full `brev` egg also imports and reexports a bunch of other eggs, including the aforementioned `clojurian` and `miscmacros`. ## Making macros Chicken has syntax-rules macros and ir-macros. Let's shave off some of the boiler plate so that it's easier to make macros. ### define-syntax-rules There is already the wonderful `define-syntax-rule` in `miscmacros` but here is also `define-syntax-rules`: (define-syntax-rules foo () ((foo bar) (+ bar 3)) ((foo bar baz) (* bar baz))) It's just the ultra lazy person's shorthand for: (define-syntax foo (syntax-rules () ((foo bar) (+ bar 3)) ((foo bar baz) (* bar baz)))) ### define-ir-syntax* `define-ir-syntax*` is more interesting. (define-ir-syntax* name (pattern body) ...) It uses `matchable` to dispatch between different call signatures (kinda similar to how `syntax-rules` work) while also allowing you to `inject`, `compare`, `strip-syntax` and `syntax` inside, as per usual with ir-macros. Here's an example: (define-ir-syntax* (aif test yes no) `(let ((,(inject 'it) ,test)) (if ,(inject 'it) ,yes ,no))) (aif (... expensive test ...) (car it) (print "oh! no!")) When you have multiple call-signatures, wrap pattern / body set with parens. (define-ir-syntax* ((aif #f yes no) no) ((aif test yes no) `(let ((,(inject 'it) ,test)) (if ,(inject 'it) ,yes ,no)))) ### define-ir-syntax Sometimes pattern matching is overkill or you have something else in mind. `define-ir-syntax` macros are just (define-ir-syntax name body) where the body has access to `body`, `inject`, `compare`, `strip-syntax` and `syntax`, as in the following example: (define-ir-syntax comp-prod (apply * body)) (comp-prod 2 3 4) ⇒ 24 As a rule of thumb, if you are deliberately injecting new names into the namespace that's when you are using ir-macros, and when you want to *avoid* doing that, use syntax-rules. ## Making procedures ### define-closure (define-closure bindings head body ...) This works like your normal (define head body ...) except that `bindings` are lexically closed over body. (define-closure (x 0) (counter) (inc! x)) (counter) (counter) (counter) ⇒ 1 2 3 The pairs of bindings aren't individual paren-wrapped, just alternating between name and expression. The set of bindings as a whole has parens. (define-closure (x 0 y 10) (jolly) (list (inc! x) (dec! y))) (jolly) (jolly) (jolly) ⇒ (1 9) (2 8) (3 7) ### match-define `matchable` has `match-lambda` and `match-lambda*` as shortcuts, and they’re fantastic, but let’s also add a `match-define` as a shortcut on top of them. How about these sorta Haskell-style semantics? (match-define (pat body ...) ...) Here's an example: (match-define ((my-map proc ()) '()) ((my-map proc (x . xs)) (cons (proc x) (my-map proc xs)))) (my-map - (iota 4)) ⇒ (0 -1 -2 -3) Works with curried define too, of course: (match-define (((my-map proc) ()) '()) (((my-map proc) (x . xs)) (cons (proc x) ((my-map proc) xs)))) ((my-map -) (iota 4)) ⇒ (0 -1 -2 -3) (map (my-map -) '((1 2 3) (10 20 30) (100 200 300))) ⇒ ((-1 -2 -3) (-10 -20 -30) (-100 -200 -300)) (Limitation: This implementation only destructures the outer argument list. For future versions it would be awesome to be able to pattern match on every level.) ### match-define-closure Combining `match-define` and `define-closure` into one glorious Voltron! (match-define-closure bindings (pat body) ...) Here's an example: (match-define-closure (x 0) ((counter) (inc! x)) ((counter 'reset) (set! x 0))) (counter) (counter) (counter 'reset) (counter) (counter) ⇒ 1 2 1 2 Here is another example, the arity-table from Software Design for Flexibility. (match-define-closure (ht (make-hash-table)) ((arity proc) (hash-table-ref ht proc)) ((arity proc a) (hash-table-set! ht proc a))) (arity cons 2) (arity cons) ⇒ 2 ### `call-table`, `call-table*`, `call-vector`, `call-string` and `call-list` The previous construct is generally useful so let's just provide it as `call-table`. (define arity (call-table)) (define color (call-table)) (arity cons 2) (color cons 'blue) (map (cut <> cons) (list arity color)) ⇒ (2 blue) `call-table` takes two optional keyword argument, `default:`, to set the default response for unknown keys, and `seed:` which can be a hash-table or an alist, and defaults to empty. There is also `call-table*` which by default cons its values to a list instead of replacing them. It takes four keyword arguments. `proc:` which defaults to `cons`, initial which defaults to `'()`, and unary which defaults to `#f`, and `seed:` as above. Both versions of call-table lets you access the underlying hash-table by calling them with no arguments, and to set them by calling them with the keyword argument `update:`. (color update: my-other-hash-table) [Full documentation for call-tables](https://idiomdrottning.org/call-table) [Full documentation for callable arrays](https://idiomdrottning.org/call-vector) ### call-key* Sometimes you think `call-table` is convenient but you only need one key. For `call-key`, just use `make-parameter`. But `call-key*` is awesome since it accumulates its values. It has the same `proc`, `unary`, and `initial` keyword arguments as `call-table*`. It doesn't have `seed` because the idea is that you just use `inititial`. The generated procedure has `update` (which takes a new list as argument) and `get` (which you only need for `unary` call-keys). (define horses (call-key*)) (horses 'ruby) (horses 'kind-girl) (horses 'tornado) (horses) ⇒ (tornado kind-girl ruby) ### define-some This is for making functions that implicitly returns '() on an `empty?` first argument. In other words, it define a body for patterns with **some** non-empty value as first argument, hence the name `define-some`. For example, (define-some (descseq num) (cons num (descseq (sub1 num)))) is shorthand for (define (descseq num) (if (empty? num) '() (cons num (descseq (sub1 num))))) so (descseq 5) ⇒ (5 4 3 2 1) ### define-curry It's nice that you can make specific curries with the SRFI-219 style define heads (which is implemented per default in Chicken). That's nice if you know exactly how many stragglers and how many immediate args you have, but sometimes you need the currying itself to be arbitrary arity. Let's say you already have something like: (define (foo bar baz bax) (print baz) (+ bar baz bax)) but you realize you need arbitrary-arity currying. Just change it to use `define-curry` instead of `define`: (define-curry (foo bar baz bax) (print baz) (+ bar baz bax)) (= (foo 100 20 3) ((foo 100) 20 3) ((foo 100 20) 3) ((foo) 100 20 3) (((foo) 100) 20 3) (((foo 100) 20) 3) ((((foo) 100) 20) 3)) Prints seven 20 and returns `#t`. It only works when `foo` otherwise would have fixed arity. ### `c` a.k.a. `🍛` a.k.a. `@>` This isn't the traditional c-combinator from mockingbirds and such. It's just a one-letter spelling of "curry". It's a function combinator. ((c + 1 20 300) 4000 50000) ⇒ 54321 I also exported it using the name 🍛 for those who find emoji names more comfortable to use due to namespace issues. I later found out that `@>` from the `holes` egg is same the combinator as this. It has arbitrary arity and can work on arbitrary arity functions, but isn't recursive to multiple levels. ### fn (fn body ...) is shorthand for (lambda some-basic-bindings body ...) where some-basic-bindings is one of - args - (x . rest) - (x y . rest) - (x y z . rest) and the fn macro automatically figures out which of those four you mean. ### over (over body ...) is shorthand for (cut map (lambda some-basic-bindings body ...) <>) except that the map can take any number of lists and that `i` is also anaphorically bound to the list index in `body`. Here is an example: ((over (+ x x y i)) '(10 20 40) '(3 6 9)) ⇒ (23 47 91) ### as-list Here is a functional combinator for Scheme that lets its arguments treat their arguments as if they were lists. ((as-list (c filter odd?)) 130752) ⇒ 1375 ((as-list cdr reverse) 23311358) ⇒ 5311332 ((as-list delete-duplicates) 23311358) ⇒ 23158 (define (vowel? l) ((as-list (c member l)) "aeiou")) ((as-list (c filter vowel?)) "magnetic mountaintop") ⇒ “aeiouaio” Together with `over`: ((as-list (over (if (vowel? x) x (char-upcase x)))) "fleet foxes") ⇒ “FLeeT FoXeS” ### c_r Sometimes you just need an arbitrarily long tree dereferencer. (c_r cddadadaddddar) makes `cddadadaddddar` real. Works for any sequence of a's and d's. ## Making values ### with-result This is something that is sometimes cozy: (with-result (print 1 2 (save 3) 4 5 6) (print 7 8)) Prints 123456 and 78, returns 3 ### empty? This is a generic predicate to see if a string is "", a list is '(), a number is 0 etc. ### `eif` and `econd` `eif` is a version of `if` (or, to be precise, of `aif` since it anaphoric) that treats empty things as falsy. (eif "" it 'no) ⇒ no `econd`, similarly, is an "empty is falsy" version of `acond`. ### like? `like?` is a unary curried version of `equal?` ### is? `is?` is a unary curried version of `eq?` ## Doing stuff ### for-each-line (for-each-line filename body ...) `body` is called for its sideeffects once per line of text in `filename` with the variable `line` anaphorically bound to that line. For example: (for-each-line "/tmp/foo" (print line)) ## Source code git clone https://idiomdrottning.org/brev-separate