Namudon'tdie
Namudon'tdie

Reputation: 306

Why are calls to `defmacro` evaluating to None?

I was writing the following pieces of code:

(require [hy.contrib.walk [let]])


(defn maybe? [command-text]
  (let [splitted (.split command-text " ")]
    (= (get splitted 0) "maybe")))


(defn if? [command-text]
  (let [splitted (.split command-text " ")]
    (+ (get splitted 0) "if")))

... until I realized I was doing something repetitive, so I wanted to factor out the pattern:

(import [hy [HySymbol]])


(defmacro command-dispatcher [command-type]
  `(defn ~(HySymbol (+ command-type "?")) [command-text]
     (let [splitted (.split command-text " ")]
       (= (get splitted 0) ~command-type))))

However, if I evaluate (command-dispatcher "maybe") in HyREPL, I get a None.

=> (command-dispatcher "maybe")
def is_maybe(command_text):
    _hyx_letXUffffX3 = {}
    _hyx_letXUffffX3['splitted'] = command_text.split(' ')
    return _hyx_letXUffffX3['splitted'][0] == 'maybe'


None

This is weird, because a macro should return a HyExpression, not None. What am I missing?

Upvotes: 0

Views: 82

Answers (1)

michaeldel
michaeldel

Reputation: 2385

Your macro will not return anything but will define a function, as you can see here

(assert (not (in "is_maybe" (dir))))
(command-dispatcher "maybe")
(assert (in "is_maybe" (dir)))

An issue in your code is that you are using let, which is not available anymore according to documentation, here is a possible way to rewrite it using setv instead:

(defmacro command-dispatcher [command-type]
  `(defn ~(HySymbol (+ command-type "?")) [command-text]
       (setv splitted (.split command-text " "))
       (= (get splitted 0) ~command-type)))

You can then call this function using is_maybe (or maybe?, that's syntactic sugar), eg.

(command-dispatcher "maybe")

(print (maybe? "foo"))
(print (maybe? "maybe foo"))

Will print

False
True

Upvotes: 1

Related Questions