Locally rebinding `+` - hy

How to translate this Clojure code to Hy, so it prints 2?
It doesn't need to be like Clojure, i just want to hide + and replace it with - in local environment.
(defmacro q [expr]
`(let ~'[+ (fn [x y] (- x y))]
~expr))
(print (q (+ 3 1)))
In Clojure it prints 2 (let creates a local environment).
In Hy it prints 4.
How to make Hy print 2 also, by replacing the + with - ?
I need those local environments because i am making a DSL.

This doesn't do what you expect in Hy because + is a macro, and macro calls take precedence over function calls:
(defmacro x [] 1)
(defn x [] 2)
(print (x)) ; => 1
Your options are:
Instead of +, use a name doesn't have the same name as a core macro, like my+ or +2.
Only use your new + in contexts other than the head of an Expression (which is the only place Hy expands macro calls), such as (map + (range 10)).
In q, replace the symbol + in the input instead of just setting the variable +, as in something like
(defmacro q [expr]
(import hyrule [coll?])
(defn f [x]
(cond
(= x '+) '-
(coll? x) ((type x) (map f x))
True x))
(f expr))
(print (q (+ 3 1)))
Use defmacro to define a new macro named +. This is a bad idea because you lose access to the original + in this module, including in the expansions of macros you didn't write that expect + to have its usual meaning. Local macros are not yet implemented (#900).

Related

Defining a macro for iterate

I wanted to define a new clause for the iterate macro. Something similar to Python's range where you have a start, stop, step. Here's a first try:
(defmacro-clause (for var start start stop stop step step)
(if (minusp step)
`(for ,var from ,start downto ,stop by (- ,step))
`(for ,var from ,start to ,stop by ,step)))
It deals with increasing and decreasing ranges using the to and downto keywords of iterate. (Note that, unlike Python, these include the stop value.)
This works as desired for
(iter (for x start 5 stop 3 step -1)
(collect x))
;; => (5 4 3)
(iter (for x start 2 stop 5 step 1)
(collect x))
;; => (3,4,5)
However it fails for anything like
(let ((a 9)
(b 3)
(c -1))
(iter (for x start a stop b step c)
(collect x)))
Is it a quirk of iterate that it requires explicit numbers in these places? It has no problem with things like
(iter (for x below (+ 3 3) by (+ 1 1))
(collect x))
Concretely my question is, how can I define a new iterate clause that accepts variables which are bound to numbers in these places?
The problem is that you are trying to decide things at macro-expansion time which can't be known then, such as the sign of a variable. In particular you can't write a macro which expands into (part of) another macro depending on anything which is only known at run time, or you can, but that necessarily means you have to call the moral equivalent of eval at run-time, and ... don't do that.
Instead you have to make the decision about which way to count at run-time. This means you can't use any of the (for var from ...) or related clauses because there don't seem to be any which are agnostic about direction (why (for i from 1 to -5 by -1) doesn't work is beyond me but ... well).
So whatever clause you end up with needs to expand into a (for var next ...) clause, I think.
Here is an attempt at such. Disclaimer: not tested very much, I don't use iterate, may explode on contact, poisonous to fish.
(defmacro-driver (for v in-range a to b &optional by s)
(let ((firstp (make-symbol "FIRSTP"))
(value (make-symbol "VALUE"))
(limit (make-symbol "LIMIT"))
(step (make-symbol "STEP")))
`(progn
(with ,firstp = t)
(with ,value = (let ((v ,a))
(unless (numberp v)
(warn "doomed"))
(when (null v)
(warn "extremely doomed"))
v))
(with ,limit = (let ((v ,b))
(unless (numberp v)
(warn "also doomed"))
v))
(with ,step = (let ((v (or ,s (signum (- ,limit ,value)))))
(when (not (numberp v))
(warn "doomed again"))
(when (zerop v)
(warn "zero step"))
(when (not (= (signum v) (signum (- ,limit ,value))))
(warn "likely doomed"))
v))
(,(if generate 'generate 'for)
,v
next (if ,firstp
(progn
(setf ,firstp nil)
,value)
(progn
(incf ,value ,step)
(when (if (> ,step 0)
(>= ,value ,limit)
(<= ,value ,limit))
(terminate))
,value))))))
And now
> (iter (for i in-range 1 to 5 by 2)
(print i))
1
3
nil
> (iter (for i in-range 1 to -1)
(print i))
1
0
nil
> (iter (for i in-range 1 to 5 by -2)
(when (< i -20)
(terminate)))
Warning: likely doomed
nil
Obviously some of the checks could be better.

Using loop inside defmacro

I'm learning (common) Lisp, and as exercise, I want to implement 'xond', a cond macro, that transform this silly example:
(xond (= n 1) (setq x 2) (= n 2) (setq x 1))
into a if-else chain:
(if (= n 1) (setq x 2) (if (= n 2) (setq x 1)))
Currently, I have this macro:
(defmacro xond (&rest x) (if x (list 'progn (list 'if (pop x) (pop x)))))
that just expand the first two items in x:
(macroexpand '(xond (= x 1) (setq y 2)))
produce
(PROGN (IF (= X 1) (SETQ Y 2))) ;
Now I want to process all items in x, so I add a loop to produce a if-serie (a step toward if-else-version):
(defmacro xond (&rest x)
(loop (if x
(list 'progn (list 'if (pop x) (pop x)))
(return t))))
but then macro seems to stop working:
(macroexpand '(xond (= x 1) (setq y 2)))
T ;
What I'm missing here?
Edition
verdammelt's answer put me in the right track, and coredump's made me change my approach to an iterative one.
Now I'll implement (xond test1 exp1 test2 exp2) as:
(block nil
test1 (return exp1)
test2 (return exp2)
)
which can be done by iteration.
I'm writing this for my minimal Lisp interpreter; I have only implemented the most basic functions.
This is what I wrote. I'm using la to accumulate the parts of the output.
(defmacro xond (&rest x)
(let ((la '()))
(loop
(if x (push (list 'if (pop x) (list 'return (pop x))) la)
(progn (push 'nil la)
(push 'block la)
(return la)
)))))
with
(macroexpand '(xond (= x 1) (setq y 2) (= X 2) (setq y 1)))
result:
(BLOCK NIL
(IF (= X 2) (RETURN (SETQ Y 1)))
(IF (= X 1) (RETURN (SETQ Y 2)))
) ;
Second edition
Add a label to block and change return to return-from, to avoid conflict with other return inside arguments. Also changed push for append to generate code in the same orden as the parameters.
(defmacro xond (&rest x)
(let ((label (gensym)) (la '()) (condition nil) (expresion nil))
(setq la (append la (list 'block label)))
(loop
(if x
(setq la (append la (list
(list 'if (pop x) (list 'return-from label (pop x))))))
(return la)))))
So
(macroexpand '(xond (= x 1) (setq y 2) (= X 2) (setq y 1)))
now gives
(BLOCK #:G3187 (IF (= X 1) (RETURN-FROM #:G3187 (SETQ Y 2))) (IF (= X 2) (RETURN-FROM #:G3187 (SETQ Y 1))))
Some remarks
You do not need a progn when you only expand into a single if
The use of pop might be confusing for the reader (and the programmer too) since it mutates a place, maybe you want to start with a less imperative approach
Also, in that case I don't think a loop approach is helpful, because you need to nest the expressions that come after in the body inside a previously built form, and even though it can be done, it is a bit more complex to do that simply a recursive function or a "recursive" macro.
Here I explain both approach, starting with "recursive" macro (the quote here is because the macro does not call itself, but expands as call to itself).
Macro expansion fixpoint
If I had to implement xond, I would write a macro that expands into other calls to xond, until macroexpansion reaches a base case where there are no more xond:
(defmacro xond (&rest body)
(if (rest body)
(destructuring-bind (test if-action . rest) body
`(if ,test ,if-action (xond ,#rest)))
(first body)))
For example, this expression:
(xond (= n 1) (setq x 2) (= n 2) (setq x 1))
First macroexpands into:
(if (= n 1)
(setq x 2)
(xond (= n 2) (setq x 1)))
And eventually reaches a fixpoint with:
(if (= n 1)
(setq x 2)
(if (= n 2)
(setq x 1)
nil))
Be careful, you cannot directly use xond inside the definition of xond, what happens is that the macro expands as a call to xond, which Lisp then expands again. If you are not careful, you may end up with an infinite macroexpansion, that's why you need a base case where the macro does not expand into xond.
Macro calling a recursive function
Alternatively, you can call a recursive function inside your macro, and expand all the inner forms at once.
With LABELS, you bind xond-expand to a recursive function. Here this is an actual recursive approach:
(labels ((xond-expand (body)
(if body
(list 'if
(pop body)
(pop body)
(xond-expand body))
nil)))
(xond-expand '((= n 1) (setq x 2) (= n 2) (setq x 1))))
; => (IF (= N 1)
; (SETQ X 2)
; (IF (= N 2)
; (SETQ X 1)
; NIL))
Your xond macro ends with (return t) so it evaluates to t rather than your accumulated if expressions.
You could use loop's collect clause to accumulate the code you wish to return. For example: (loop for x in '(1 2 3) collect (* 2 x)) would evaluate to (2 4 6).
How about
(ql:quickload :alexandria)
(defun as-last (l1 l2)
`(,#l1 ,l2))
(defmacro xond (&rest args)
(reduce #'as-last
(loop for (condition . branch) in (alexandria:plist-alist args)
collect `(if ,condition ,branch))
:from-end t))
(macroexpand-1 '(xond c1 b1 c2 b2 c3 b3))
;; (IF C1 B1 (IF C2 B2 (IF C3 B3))) ;
;; T
alexandria's plist-alist was used to pair the arguments,
the intrinsic destructuring in loop used to extract conditions and branches.
The helper function as-last stacks lists together in the kind of
(a b c) (d e f) => (a b c (d e f)).
(reduce ... :from-end t) right-folds the sequence of the collected (if condition branch) clauses stacking them into each other using #'as-last.
Without any dependencies
('though, does alexandria even count as a dependency? ;) )
(defun pairs (l &key (acc '()) (fill-with-nil-p nil))
(cond ((null l) (nreverse acc))
((null (cdr l)) (pairs (cdr l)
:acc (cons (if fill-with-nil-p
(list (car l) nil)
l)
acc)
:fill-with-nil-p fill-with-nil-p))
(t (pairs (cdr (cdr l))
:acc (cons (list (car l) (cadr l)) acc)
:fill-with-nil-p fill-with-nil-p))))
(defun as-last (l1 l2)
`(,#l1 ,l2))
(defmacro xond (&rest args)
(reduce #'as-last
(loop for (condition branch) in (pairs args)
collect `(if ,condition ,branch))
:from-end t))
(macroexpand-1 '(xond c1 b1 c2 b2 c3 b3))
;; (IF C1 B1 (IF C2 B2 (IF C3 B3))) ;
;; T
The helper function pairs makes out of (a b c d e f) => ((a b) (c d) (e f)).
(:fill-with-nil-p determines in case of odd number of list elements, whether the last element would be listed (last-el) or (last-el nil) - in the latter case filled with nil).

Is there a way in the hy language to use doto on self?

hopefully someone can help me with this hy question. I am porting some python code over to hy, and was trying to figure out how I could remove some repetitive code using the doto macro. For example, look at a python class like this:
class Foo(object):
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
How could I convert this in hy to use doto?
(defclass Foo [object]
[[__init__ (fn [self x y z]
(doto self ;
(setv ...) ; What goes here?
))]])
The problem is that it looks like you normally do something like this:
(defclass Foo [object]
[[__init__ (fn [self x y z]
(setv self.x x)
(setv self.y y)
(setv self.z z))]])
I don't see a way of using (doto) on self.
That is an interesting idea. You can do this:
(doto self
(setattr "x" x)
(setattr "y" y)
(setattr "z" z))
But it's not much better. Consider defining a macro:
(defmacro vars-to-attrs [obj &rest attrs]
(let [[actions (list (map
(fn (a) `(setattr (str '~a) ~a))
attrs))]]
`(doto ~obj ~#actions)))
And then calling it like this:
(vars-to-attrs self x y z)
This might work better as a function though:
(defun vars-to-attrs-fun [obj &rest attrs]
(for [a attrs]
(setattr obj a (get (locals) a))))
And then call it like:
(vars-to-attrs-fun self 'x 'y 'z)
or, equivalent:
(vars-to-attrs-fun self "x" "y" "z")
If you just want to keep __init__'s locals, the easiest way is to directly .update the instance vars with the local vars.
(defclass Foo [object]
(defn __init__ [self x y z]
(.update (vars self) (vars))))
(By the way, the above is using our new defclass syntax from the version of Hy on Github, which won't work with the current PyPI version. [Update: it's now in the current PyPI release])
This does include all the locals, so you get a self.self, which is probably harmless, but you can del it after if you want. Hy sometimes generates locals to make statements act like expressions. These could also end up in the instance dict if you're not careful. You can avoid this by associng only the names you want:
(assoc (vars self)
'x x
'y y
'z z))
The new setv syntax also takes an arbitrary number of pairs, so you could do something like this instead:
;; new setv syntax
(setv self.x x
self.y y
self.z z)
You could pretty much do this before using tuples:
;; works in both Hy versions
(setv (, self.x self.y self.z)
(, x y z))
You can also avoid duplication in .update with a dict-comp, though this isn't usually shorter.
(.update (vars self) (dict-comp k (get (vars) k) [k '[x y z]]))
If you're still set on using doto, the correct syntax is:
(doto self
(-> (. x) (setv x))
(-> (. y) (setv y))
(-> (. z) (setv z)))
This does avoid repeating self, but it's not shorter than the aforementioned alternatives, so doto is the wrong tool for this particular job.
Update
I've made an issue for this https://github.com/hylang/hy/issues/1532
We might be adding an attach macro to Hy. I also posted an implementation if you want to try it out early.
Usage:
(defclass Foo []
(defn __init__[self x y z]
(attach self x y z)))
Since the attachment target is the first argument, attach would also work in a -> or in a doto, e.g.
(doto self
(.configure foo bar)
(attach spam eggs))

Return from a nested loop in Common Lisp

I'm trying to convert this Python code into Common Lisp:
for a in xrange(1,1000):
for b in xrange(a,1000):
c = (a**2 + b**2) ** 0.5
s = a + b + c
if s == 1000:
return a * b * c
My first attempt was:
(loop for a from 1 to 999
do (loop for b from a to 999
for c = (sqrt (+ (expt a 2) (expt b 2)))
for s = (+ a b c)
until (= s 1000)
finally return (* a b c))))
This doesn't work. My task is: when s hits 1000 make the whole expression above return (* a b c). How to return some value from a nested loop macro?
You can use block and return-from operators: block establishes a named block of code, and you can return from this block with return-from using the name of the block
(let (c s)
(block nested-loops
(do ((a 1 (1+ a))) ((= a 999))
(do ((b a (1+ b))) ((= b 999))
(setf c (sqrt (+ (expt a 2) (expt b 2)))
s (+ a b c))
(if (= s 1000)
(return-from nested-loops (* a b c)))))))
PS, I don't use loop here, I just got used to do.
Also from http://www.gigamonkeys.com/book/loop-for-black-belts.html
To allow RETURN-FROM to be used to return from a specific loop (useful when nesting LOOP expressions), you can name a LOOP with the loop keyword named. If a named clause appears in a loop, it must be the first clause. For a simple example, assume lists is a list of lists and you want to find an item that matches some criteria in one of those nested lists. You could find it with a pair of nested loops like this:
(loop named outer for list in lists do
(loop for item in list do
(if (what-i-am-looking-for-p item)
(return-from outer item))))
The Python return statement doesn't return from the loop, it returns from the whole function that the loop is contained in. In Common Lisp, a function establishes an implicit block with the same name as the function. So you can use:
(return-from function-name (* a b c))
to perform the return equivalent to the Python code.
I think your solution should work with little adjustment while trying to keep the original form of the python code
(loop named outer for a from 1 below 1000 do
(loop for b from a below 1000
for c = (sqrt (+ (expt a 2) (expt b 2)))
for s = (+ a b c)
if (= s 1000) do (return-from outer (* a b c))))
And if you wanted to enter infix equations, you can use infix library available from quicklisp with (ql:quickload :infix), and then modify the above to get
(loop named outer for a from 1 below 1000 do
(loop for b from a below 1000
for c = #i(sqrt (a^^2 + b^^2))
for s = #i(a + b + c)
if (= s 1000) do (return-from outer #i(a * b * c))))

How to store a broken-Scheme-string in an array or a vector?

I get as an input a string , and I want to store it in an array or
a vector , so I would be able to check the values of the broken string .
Here I break the string into chars :
(define (dealBreaker str) (string->list str)) ; break the string into chars
But when I try to declare a simple vector :
(define (myVector (make-vector 4 (/ 1 2))))
I get this : #%plain-lambda: not an identifier in: (make-vector 4 (/ 1 2))
How can I declare a vector called someVector for the broken characters from dealBreaker method above ?
Try this, for some str string:
(define (dealBreaker str)
(list->vector (string->list str)))
(define myVector (dealBreaker "some string"))
myVector
=> '#(#\s #\o #\m #\e #\space #\s #\t #\r #\i #\n #\g)
The above will create a new vector from the characters in the string, is that what you need?
The problem here is that define should be
(define identifier value)
but right now you have
(define (identifier value))
So try
(define myVector (make-vector 4 (/ 1 2)))
It's a little confusing, because in Scheme, define is overloaded, there's also
(define (functionName formals) body)
but that's purely syntactical sugar for
(define functionName
(lambda formals body))
Side note: Several beginner scheme textbooks recommend using the lambda version since it's more explicit.
In this case though, just do:
(define myVec (list->vector (dealBreaker str)))
The immediate problem you're having with myVector appears to be due to a misplaced paren - try this instead and see if it resolves the 'plain-lambda' error:
(define myVector (make-vector 4 (/ 1 2)))
On the question of converting the 'dealBreaker' string to a vector, you should be able to do this:
(define (someVector dealBreakerList) (list->vector dealBreakerList))
(someVector (dealBreaker "someString"))
Or if you want 'someVector' as the complete function:
(define (someVector str) (list->vector (string->list str)))
(someVector "someString")

Resources