What is the equivalent of `if x in y` in hy? - hy

I can't seem to find a builtin (or equivalent) in hy that lets me check for something without handling an exception
I would like to write something like:
(setv foo {:a 1 :b 2})
(if (in foo :c)
(foo)
(boo))
(:c foo) and (get foo :c) both result in an exception

Hy has an equivalent for all the Python operators. Hy uses prefix notation for all operators, but doesn't change the order of the operands from how they would be in infix notation. So (- 10 8) in Hy is 2, same as 10 - 8 in Python.
This goes for the in operator as well. (in :c foo) is like HyKeyword('c') in foo. Think of it like in(:c, foo), not "In foo, :c?".

instead of (get foo :c) use (.get foo :c) and compare the None if the c keyword does not exist.
(setv foo {:a 1 :b 2})
(if (!= (.get foo :c) None)
(foo)
(boo))

Related

Locally rebinding `+`

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

`self` can not use as arguments of a hy macro

The following macro tries to assign a member variable from init argument.
But
name 'self' is not defined
(defmacro optional_assign [x &optional [base self]]
`(lif ~x (setv (. ~base ~x) ~x) (setv (. ~base ~x ) None) ))
(defclass clsa []
(defn __init__ [self &optional y]
(optional_assign y)
))
(setv insa1 (clsa 123))
(print insa1.y) ;;=>123
(setv insa2 (clsa))
(print insa2.y) ;;=>None
The default argument is evaluated like an ordinary expression, so you want [base 'self], not [base self].
Also, you're missing a ~ for the first mention of x in the body.

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

Difference between gcc and Microsoft preprocessor

I discovered that Microsoft Visual Studio compiler and gcc preprocess the following small snippet differently:
# define M3(x, y, z) x + y + z
# define M2(x, y) M3(x, y)
# define P(x, y) {x, y}
# define M(x, y) M2(x, P(x, y))
M(a, b)
'gcc -E' gives the following:
a + {a + b}
, while 'cl /E' issues a warning about missing macro argument and produces the following output:
a + {a, b} +
It seems that commas that came from nested macro expansions are not considered to be argument separators. Unfortunately, I found no description of the algorithm implemented in cl preprocessor, and so I'm not sure that my suggestion is correct. Does anyone know how cl preprocessor works and what's the difference between its algorithm and gcc's? And how the observed behaviour can be explained?
# define M3(x, y, z) x + y + z
# define M2(x, y) M3(x, y)
# define P(x, y) {x, y}
# define M(x, y) M2(x, P(x, y))
M(a, b)
Let us roll this out manually, step by step:
M(a, b)
--> M2(a, P(a, b))
--> M2(a, {a, b})
The standard says:
The individual arguments within the list are separated by comma
preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate
only parentheses are mentioned, so ...
--> M3(a, {a, b})
--> a + {a + b}
Important:
M3(a, {a, b})
Here, according to the previous quote from the standard, three "arguments" are passed to M3 (using single-quotes to describe tokens/arguments):
M3('a', '{a', 'b}')
which are expanded to
'a' + '{a' + 'b}'
And this is what cpp (4.6.1) gives verbatim:
# 1 "cpp.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "cpp.cpp"
a + {a + b}
cpp (or gcc and g++) are correct, MSVC isn't.
As a nobleman make sure a bug report exists.
The only logic that explains such a behavior looks like this.
CL way:
M(a,b)
M2(a,P(a,b))
M3(a,P(a,b))
M3(a,{a,b}) -> M3 gets 2 arguments ( 'a' and '{a,b}') instead of 3.
| \ /
arg1 |
arg2
Gcc way:
M(a,b)
M2(a,P(a,b))
M3(a,P(a,b))
M3(a,{a,b}) -> Gcc probably thinks there are 3 arguments here ('a', '{a', 'b}').
| | |
arg1 | |
arg2 |
arg3
I think gcc gets it right, what Microsoft does is incorrect.
When macro substitution is done for the line
M2(a, P(a, b))
the standard (section 6.10.3.1) requires that before replacing the second parameter ("y") in the macro's replacement list ("M3(x, y)") with its argument ("P(a, b)"), macro replacement is to be performed for that argument. This means "P(a, b)" is processed to "{a, b}" before it is inserted, resulting in
M3(a, {a, b})
which is then further replaced to
a + {a + b}

Looping through args of macro

I am trying to write a macro in Clojure that allows for evaluation of a series of simple "def" expressions. I am a n00b when it comes to macros. The idea is that
(my-defs y1 1
y2 "taco")
should expand to
(do (def y1 1) (def y2 "taco"))
The following code accomplishes this for the special case of two defs
(defmacro my-defs
[& args]
`(do
(def ~(first args) ~(second args))
(def ~(nth args 2) ~(nth args 3) )))
which is nice, but I am having trouble generalizing this. I tried out a few naive things involving looping through bindings of the elements of (partition 2 args) but I always got garbage (I know this isn't very specific but the diversity and extent of the garbage seemed a bit too much to report here). How do I loop over these are and evaluate my defs?
P.S.
The macro my-defs is a toy. What i really want to accomplish in the end is a littel helper macro to instantiate a bunch of multimethod instances. Currently I have large chunks of code that look like
(defmethod f [A B] [x] "AB")
(defmethod f [A A] [x] "AA")
(defmethod f [C B] [x] "CB")
which is a little unsightly. It would be nice if I could do something like
(defmethods f
[A B] [x] "AB"
[A A] [x] "AA"
[C B] [x] "CB")
instead.
It looks to me like you're looking for the ~# macro expansion/unquote.
(defmacro defmethods [n & defs]
`(do ~#(map (fn [[a1 a2 a3]]
`(def ~n ~a1 ~a2 ~a3))
(partition 3 defs))))

Resources