Getting a scheme macro keyword to match only if at least two arguments are given to it - macros

I am trying to implement a keyword (named =) for a macro transformer (named latex) which is intended to match only if at least two arguments are given to it. My attempt is:
((_ (= a b))
`(,#(latex a) "=" ,#(latex b)))
((_ (= a b ...))
`(,#(latex a) "=" ,#(latex (= b ...))))
but this implementation matches when only one argument is given to = and gives an undesirable result. A table of outputs for various inputs is given below.
Input to latex
Displayed Result
comment
=
=
ok (no match)
(=)
(=)
ok (no match)
(= a)
a=(=)
bad match. result should be (= a)
(= a b)
a=b
ok (match)
(= a b c)
a=b=c
ok (match)
(= a b c d)
a=b=c=d
ok (match)
You may view the source file or the project page if you require more context.

Related

Match Hash Tables in Typed Racket

I'm trying to match against a hash table in typed racket, but I keep getting the following error. The code works fine in untyped racket and I've tried changing it up some to no effect. The error looks like it's happening somewhere after the match macro gets expanded but I'm not familiar enough with racket to understand where or how to debug the issue.
Is is possible to use the hash-table pattern in typed racket?
(match (make-hash '((a . 2) (b . 3) (c . 2)))
[(hash-table _ ...) #t])
Type Checker: Polymorphic function `hash-map' could not be applied to arguments:
Domains: HashTableTop (-> Any Any c) Any
HashTableTop (-> Any Any c)
(HashTable a b) (-> a b c) Any
(HashTable a b) (-> a b c)
Arguments: (Mutable-HashTable Symbol Integer) (All (a) (-> a * (Listof a)))
it's impossible.
in the match macro, the hash-table form expands to syntax that includes the hash-map function, viz (lambda (e) (hash-map e list)). this is correct but its type is too abstract for typed racket to infer it. for the type checker to be satisfied, we'd need:
(lambda #:forall (k v) ([e : (HashTable k v)])
(hash-map e
(λ ([k : k] [v : v])
(list k v))))
there's no practical way to specify this, so the hash-table matcher is unusable in typed racket.
if a for loop is usually best, e.g.
(for ([(k v) (make-hash '((a . 2) (b . 3) (c . 2)))] #:when (even? v))
(printf "~a and ~a~n" k v))
or else something like (hash-keys m)
otherwise, positional matching requires advanced knoweldge of typed racket. for example, the following function, hash-set/cond, takes a hash table and arguments of the form (flag k v) ... and updates (if key already in table) or inserts (if key not already in table) each k/v pair if its associated flag is truthy:
(: hash-set/cond (∀ (k v) (->* ((HashTable k v))
#:rest-star (Any k v)
(HashTable k v))))
(define (hash-set/cond ht . args)
(let loop ([ht : (HashTable k v) ht]
[args : (Rec r (U (List* Any k v r) Null)) args])
(if (null? args)
ht
(loop (if (car args)
(hash-set ht (cadr args) (caddr args))
ht)
(cdddr args)))))
e.g.
(hash-set/cond (hash 'a 20 'b "yes")
(even? 3) 'a 10 ; 3's not even, so 'a isn't modified
#t 'b "canary" ; necessarily set 'b to "canary"
'im-a-truthy-value! 'c 'new-value) ; ditto
returns #hash((a . 20) (b . "canary") (c . new-value)).
so if you end-up using typed racket a lot and want to use this kind of functionality, then it can be very useful in certain places! still, typed racket's type system can represent—but not handle—certain recursive hash table types. this is because, when checking the type of the value, hash? cannot refine the type of the hash table beyond it being a hash table with some type of key and value, i.e. hash? : (-> Any Boolean : HashTableTop) instead of (-> Any Boolean : (HashTable k v)). this makes recursing over particular recursively defined JSON schemata impossible. in these cases you must use untyped racket, though the saving grace here is that racket contracts can handle such complex definitions.
if your project is heavily based on complex hash tables, then clojure or janet are likely better language choices.

What's difference between case and match?

I was confusing about the difference between match and case. In the document, it mentions that match supports general pattern matching.
> (define (m x)
(match x
[(list a b c)
#:when (= 6 (+ a b c))
'sum-is-six]
[(list a b c) 'sum-is-not-six]))
> (m '(1 2 3))
'sum-is-six
> (m '(2 3 4))
'sum-is-not-six
For this example, I thought I could rewrite it using case expression. But seems it's quite complicated. I have to get the length of the input x, and maybe a lambda function to get the sum of the elements of x and compare it with 6.
So I guess we prefer match when doing pattern matching. Is it true? Any difference other than that?
You said it yourself, match does general pattern matching (a very powerful concept!) whereas case only checks if a value belongs in one of several lists of possible (implicitly quoted) values. All that case does is syntactic sugar for a cond with multiple conditions, for example:
(case (+ 7 5)
[(1 2 3) 'small]
[(10 11 12) 'big]
[else 'other])
... is roughly equivalent to:
(let ((val (+ 7 5)))
(cond ((or (equal? val 1) (equal? val 2) (equal? val 3))
'small)
((or (equal? val 10) (equal? val 11) (equal? val 12))
'big)
(else 'other)))
Whereas match does some complex matching; it checks if a value is one of several possible patterns, it's not only about comparing values for equality, it also checks the type and "shape" of the value against the pattern, and we can even add additional constraints using #:when. To see how complex this can be check under the grammar part of match's documentation.
There are two differences:
match is a lot more powerful than case. case doesn't have "patterns" in the way match does, and it implicitly quotes the datums in each "branch question". It only compares the quoted form of the datum against the value, like a switch statement. match has a different and much richer pattern language.
The x in each branch-question of these two examples
(case 5
[(x) 10]
[else 'fail])
;=> 'fail
(case 'x
[(x) 10]
[else 'fail])
;=> 10
Is implicitly quoted, as the symbol 'x. In match terms, this is equivalent to
(match 5
['x 10]
[_ 'fail])
;=> 'fail
(match 'x
['x 10]
[_ 'fail])
;=> 10
Where quoting is one of many options for creating patterns, not the default. If you leave out the quote in a match, x is no longer a symbol; it is a wildcard that matches anything and defines x as the result.
(match 5
[x (+ x 1)])
;=> 6
This could never happen with case because of case's implicit quoting.
case branch-questions have multiple datums per branch.
These datums must be wrapped in parentheses.
(case expr
[(datum ...) answer]
...)
Where match has only one pattern per branch (no parentheses)
(match expr
[pattern answer]
...)

Lisp function to return a number double and then the same number doubled plus one

I am totally new to lisp and have no idea how I'll create this function.
This is the pseudo code I created to help me solve it
Binary tree children
; This function returns the children of binary tree node
; e.g., 3 -> (6,7)
; e.g., 11 -> (22,23)
(defun tree-node(x))
The function is intended to take in a number, double it, and then double it and add 1. Please help.
To double a number (which is stored in a variable named n here): (* 2 n).
To add one: (1+ n). Note that 1+ is the name of a function. It is the same as (+ n 1).
Now, let's say that you have some scope (e. g. a function body) where you have a variable named n. You now create a new variable d using let:
(let ((d (* n 2)))
…)
This new variable is in scope for the body of the let (indicated by … above).
Now we create another variable d1, which is one more. We need to use let* now, so that the scope of d is not just the body, but also the binding forms of the let*:
(let* ((d (* n 2))
(d1 (+ d 1)))
…)
The function should maybe be called child-indices:
(defun child-indices (n)
(let* ((d (* n 2))
(d1 (+ d 1)))
…))
The bodies of many forms like defun and let are so-called implicit progns, which means that these forms return the value of the last expression in their body. So, whatever forms we put into the place marked … above, the value (or values, but let's keep that aside for now) of the last is the return value of the function.
There are several ways to do a “return this and then that”, but we'll use a list for now:
(defun child-indices (n)
(let* ((d (* n 2))
(d1 (+ d 1)))
(list d d1)))

Common Lisp: first returns first, but last returns a list of last -- huh?

I'm not getting this first/last thing in Common-Lisp. Yes, I see how it works, but I don't get WHY it works that way.
Basically, to get the first item in a list, I can use (first mylist). However, if I want the last item, (last mylist) doesn't give me that; instead, it gives me a list containing the last item in my list!
(I'm using Clozure-CL, which has a few other oddities that seem like bugs to me but, since I'm a Lisp-n00b, I'm trying not to fall for the old "the interpreter is broken!" trick :) )
So, for example:
? (setq x '((1 2) (a b)))
=> ((1 2) (A B))
? (first x)
=> (1 2) ; as expected
? (last x)
=> ((A B)) ; why a list with my answer in it?!
? (first (last x))
=> '(A B) ; This is the answer I'd expect from plain-old (last x)
Can someone help me understand why last does this? Am I using these items incorrectly? Is first really the odd-ball?!
Thanks!
In Common Lisp last is supposed to return a list, from the documentation:
last list &optional n => tail
list---a list, which might be a dotted list but must not be a circular list.
n---a non-negative integer. The default is 1.
tail---an object.
last returns the last n conses (not the last n elements) of list. If list is (), last returns ().
For example:
(setq x (list 'a 'b 'c 'd))
(last x) => (d)
And yes, this is counterintuitive. In other flavors of Lisp it works as the name suggests, for example in Racket (a Scheme dialect):
(define x '((1 2) (a b)))
(first x) => '(1 2)
(last x) => '(a b)
(define x (list 'a 'b 'c 'd))
(last x) => 'd
Returning the last element is not very useful except to access the last element; returning the last cons lets you do something like this:
(let ((x (list 1 2 3)))
(setf (cdr (last x)) '(4))
x)
=> '(1 2 3 4)
while you can still access the last element as (car (last x)).
Common Lisp's misnamed function last gives you the last cons.
It should probably be called tail, as there is a function tailp, but my guess is that this name stuck for historical/compatibility reasons.
Generally, it gives you the nth tail of a list, or the nth cons before the end of the list.
This is just the way it is. first and last are not a complementary pair of operations. last is more closely related to rest and nthcdr. There is also butlast which constructs a new list that omits the last item from the given list.
first versus last is nothing compared to how get and getf have nothing to do with set and setf.

Which object the function nth access to when applied to functional argument in Common Lisp?

I have some problem using accessor function nth. I pass a list to some function and make new binding to an element of the list in the function with nth, then when I call the list out of the function, it is modified, and it's not what I want! What happens?
Some examples
(defun test (x) (incf x)) => TEST
(setq a 1) => 1
(test a) => 2
a => 1
I understand what's going on above, but if we change everything to lists, something happens that I can't understand
(defun test (x) (incf (nth 0 x))) => TEST
(setq a '(1)) => (1)
(test a) => 2
a => (2)
I expected a to be (1), why it has been modified? I also tried other functions like car and first, result is the same.
PS, I tried it in Lispworks and SBCL, same result.
(defun test (x) (incf x)) => TEST
(setq a 1) => 1
(test a) => 2
a => 1
You pass 1 to test. Within test you modified the local variable x. a is not changed and can't be changed that way - we pass the value of a not a reference to a.
(defun test (x) (incf (nth 0 x))) => TEST
(setq a '(1)) => (1)
(test a) => 2
a => (2)
You pass the list (1) to test. The list is not copied. The local variable x points to the first cons cell in the list. You then modify the car of the first cons cell to 2. Since the list is not copied, you modify the passed list. a also points to the first cons cell of that list. So it is also (2).
If you don't want anything to be modified, don't use incf. Use 1+. The only reason to use incf is because you want its side-effect.
As to why this is happening, arguments are evaluated before being passed to a function. When you call test with a being 1, you are passing the value 1, which cannot be modified. When a resolves to a list, you are passing a list, which can be setf'd all over the shop, if you've chosen to use destructive functions.
See the documentation on nth. nth returns a place that setq can then operate on.
nth may be used to specify a place to setf. Specifically,
(setf (nth n list) new-object) == (setf (car (nthcdr n list)) new-object)