0

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.

Kodiologist
  • 2,984
  • 18
  • 33
Takis
  • 8,314
  • 2
  • 14
  • 25

1 Answers1

1

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:

  1. Instead of +, use a name doesn't have the same name as a core macro, like my+ or +2.

  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)).

  3. 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)))
    
  4. 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).

Kodiologist
  • 2,984
  • 18
  • 33
  • thank you for your time and answer i will try to see those alternatives, its very useful when making DLS's to have this type of local environments to avoid things like `my+` and just use `+` instead. – Takis Nov 19 '22 at 23:04