Operator precedence in infix notation by automatic parenthesizing

| categories: hylang | tags:

I am continuing some investigation in getting operator precedence right with infix notation. You can fully parenthesize your expressions for this, but it is tedious and hard to read. Apparently in Fortran I (yep, one) the compiler would expand each operator in an expression with a sequence of parentheses to get the precedence right (https://en.wikipedia.org/wiki/Operator-precedence_parser )!

Roughly, these were the rules.

  • replace + and – with ))+(( and ))-((, respectively;
  • replace * and / with )*( and )/(, respectively;
  • add (( at the beginning of each expression and after each left parenthesis in the original expression; and
  • add )) at the end of the expression and before each right parenthesis in the original expression.

So this

a * b + c ^ d / e

becomes

((((a))*((b)))+(((c)^(d))/((e))))

Not too pretty, but correct! The wikipedia page provides an example C program to implement this, and we adapt it here for hy. The idea is to take an expression as a string, parenthesize it, and then we could eval it.

(defn parenthesize [input]
  "Fully parenthize the input string."
  (let [s ""]
    (+= s "((((")
    (for [(, i char) (enumerate input)]
      (cond
       [(= char "(")
        (+= s "((((")]
       [(= char ")")
        (+= s "))))")]
       ;; rewrite ^ to **
       [(= char "^")
        (+= s ")**(")]
       [(= char "*")
        (+= s "))*((")]
       [(= char "/")
        (+= s "))/((")]
       [(= char "+")
        (if (or (= 0 i) (in (get input (- i 1)) ["(" "^" "*" "/" "+" "-"]))
          (+= s "+ ")
          (+= s ")))+((("))]
       [(= char "-")
        (if (or (= 0 i) (in (get input (- i 1)) ["(" "^" "*" "/" "+" "-"]))
          (+= s "- ")
          (+= s ")))-((("))]
       [true
        (+= s char)]))
    (+= s "))))")
    s))

Let's try it out.

(import [infix [*]])

(print (parenthesize "a * b + c ^ d / e"))
((((a ))*(( b )))+((( c )**( d ))/(( e))))

For comparison:

((((a))*((b)))+(((c)^(d))/((e))))

Spaces aside, it looks like we got that right. The spaces should not be a problem for lisp. This is another strategy to get infix notation with operator precedence! Let's see some examples.

(import [infix [*]])
(require infix)

(print (eval (nfx (read-str (parenthesize "1 + 2 * 5")))))
(print (eval (nfx (read-str (parenthesize "1 * 2 + 5")))))
(print (eval (nfx (read-str (parenthesize "1 * 2 + 2^2")))))
11
7
6

We can get that string representation easy enough.

(import [infix [*]])
(require infix)

(print (eval (nfx (read-str (parenthesize (stringify `(1 + 2)))))))
3

This too is worthy of simplifying the notation with a function.

(defn NFX [code &optional [globals (globals)]]
  "Evaluate the infix CODE.
CODE is stringified, parenthesized, read back and infixed."
  (import infix)
  (import serialize)
  (eval (infix.nfx
         (read-str
          (infix.parenthesize
           (serialize.stringify code)))) globals))
(defmacro NFX [code]
  "Evaluate the infix CODE.
CODE is stringified, parenthesized, read back and infixed."
  `(do
    (import infix)
    (import serialize)
    (eval (infix.nfx
           (read-str
            (infix.parenthesize
             (serialize.stringify ~code)))))))

Here is a simple example.

;(import [infix [*]])
(require infix)

(print (NFX `(1 + 2 * 5)))
(print (NFX `((1 + 2) * 5)))

(import [numpy :as np])
(print (NFX `(1 + (np.exp 2))))

; not working because of infix
;(print (NFX `(1 + (np.linspace 0 1 5))))

;; But this is ok since no infix mangling happens.
(let [a (np.linspace 0 1 5)]
  (print (NFX `(1 + a))))
11
15
8.38905609893
[ 1.    1.25  1.5   1.75  2.  ]

That is slightly heavy still, and we can fix it with a new reader macro.

(defreader m [code]
 `(do
    (import infix)
    (import serialize)
    (eval (infix.nfx
           (read-str
            (infix.parenthesize
             (serialize.stringify ~code)))))))

Since we return code in that reader macro, we have to quote the code. This is debatably more concise than the NFX macro.

(require infix)

(print #m`(1 + 2 + 5))
(print #m`(1 + 2 * 5))
(print #m`((1 + 2) * 5))

(import [numpy :as np])
(print #m`((1 + (np.exp 2))))

;; these are all the same
(print (+ 1 (np.exp 2) (* 2 5)))
(print #m(`(1 + (np.exp 2) + 2 * 5)))
(print (NFX `(1 + (np.exp 2) + 2 * 5)))
8
11
15
8.38905609893
18.3890560989
18.3890560989
18.3890560989

1 Another test of a real problem

Here is another test of using an infix notation, this time with operator precedence. Note the use of ^ for exponentiation. The parenthesize function assumes single character operators, and would take some work to use **. Note we still need the space between - and x to avoid a mangling issue with _x in hy.

(import [numpy :as np])
(import [scipy.integrate [odeint]])
(import [scipy.special [jn]])
(import [matplotlib.pyplot :as plt])

(import [infix [*]])
(require infix)

(defn fbessel [Y x]
  "System of 1st order ODEs for the Bessel equation."
  (setv nu 0.0
        y (get Y 0)
        z (get Y 1))

  ;; define the derivatives
  (setv dydx z
        ;; the Python way is: "1.0 / x**2 * (-x * z - (x**2 - nu**2) * y)"
        dzdx #m`((1.0 / x^2) * ((- x) * z - (x^2 - nu^2) * y)))
  ;; Here is what it was with prefix notation
  ;; dzdx (* (/ 1.0 (** x 2)) (- (* (* -1 x) z) (* (- (** x 2) (** nu 2)) y))))
  ;; return derivatives
  [dydx dzdx])

(setv x0 1e-15
      y0 1.0
      z0 0.0
      Y0 [y0 z0])

(setv xspan (np.linspace 1e-15 10)
      sol (odeint fbessel Y0 xspan))

(plt.plot xspan (. sol [[Ellipsis 0]]) :label "Numerical solution")
(plt.plot xspan (jn 0 xspan) "r--" :label "Analytical solution")
(plt.legend :loc "best")

(plt.savefig "bessel-infix-m.png")

I wonder if there is actually some ambiguity in the expression or how it is parenthesized. We get the right answer with:

(1.0 / x^2) * ((- x) * z - (x^2 - nu^2) * y)

but not with:

1.0 / x^2 * ((- x) * z - (x^2 - nu^2) * y))

Let's see if we can see why. Consider 1 / x * a. This should probably be evaluated as (1 / x) * a. This shows the algorithm does not do that.

(import [infix [*]])

(print
 (nfx
 (read-str
 (parenthesize
  (stringify `(1 / x * a))))))
;   `(1.0 / x^2 * ((- x) * z - (x^2 - nu^2) * y)))))))
(u'/' 1L (u'*' u'x' u'a'))

That reads: 1 / (x * a)

If we had a layer of parentheses we get the right answer.

(import [infix [*]])

(print
 (nfx
 (read-str
 (parenthesize
  (stringify `((1 / x) * a))))))
;   `((1.0 / x^2) * ((- x) * z - (x^2 - nu^2) * y)))))))
(u'*' (u'/' 1L u'x') u'a')

This reads (1 / x) * a. Our algorithm doesn't do exactly what we expect here. I guess this could be a general issue of neighboring operators with equal precedence.

Related to this, the Wikipedia page points out this example:

- a ^ 2

What does this mean? It is either (-a)^2 or -(a^2). The second is correct based on normal precedence, but the algorithm gives the unary operator - a higher precedence.

(import [infix [parenthesize]])

(print (parenthesize "- a ^ 2"))
(print (parenthesize "- (a ^ 2)"))
((((-  a )**( 2))))
((((-  ((((a )**( 2))))))))

To get the right thing, you need to use parentheses. Sometimes I do that in real code anyway to make sure what I want to happen does. Maybe some of this can be fixed in our parser function. Probably for another day.

Copyright (C) 2016 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter

Getting towards an infix notation for hy

| categories: hylang | tags:

Engineers need infix notation. It's a bold statement I know, but I am an engineer, teach engineers, and write a fair bit of mathematical programs. Your typical engineer is not a programmer, and just wants to write an equation they way we would write it on paper. It is hard to undo 20+ years of education on that point! So, here we consider how to adapt hy to use infix notation.

In a recent post gilch suggested using strings with the builtin python eval function. There are some potential downsides to that approach including the overhead of byte-compiling each time it is eval'd, but the payoff is operator precedence, and doing it like you would do it in Python.

1 using strings

UPDATE: Thanks to some help from Jiege Chen I updated this section to solve the namespace issues previously discussed. That resulted in quite a bit of improvement. Thanks Jiege!

Here is one implementation.

(def py-eval (get __builtins__ "eval"))

And how to use it.

(import [infix [*]])

(print (py-eval "2+3*5"))

(import [numpy :as np])
(print (py-eval "2 * np.exp(np.pi / 2)"))
17
9.62095476193

We can eliminate the need for quotes (") with the stringify code we previously developed.

(import [serialize [*]])
(import [infix [*]])

(print (py-eval (stringify `(2+3*5))))
(print (py-eval (stringify `(2 + 3 * 5))))

(import [numpy :as np])
(print (py-eval (stringify `(2 * np.exp(np.pi / 2)))))
17
17
9.62095476193

Let's just take that one more step with a new reader macro to tighten the syntax up. A critical feature of this reader macro is that it expands to code evaluated in the namespace where it is used. Nothing gets evaluated in the macro. That occurs in another namespace, where most things in a script are not available.

(defreader p [code]
  `(do
    (import [serialize [stringify]])
    (import [infix [py-eval]])
    (py-eval (stringify ~code))))

(defmacro py [code]
  `(do
    (import [serialize [stringify]])
    (import [infix [py-eval]])
    (py-eval (stringify ~code))))

Now we can use it like this. We have to require the infix module to get the reader macro. It seems unfortunate to me we still have to quote the code. Later I show an example where that isn't necessary, so there must be some subtle difference I have not found yet.

;; we have to require to get the reader macro
(require infix)

(import [numpy :as np])
(print #p`(2 + 3 * 5))
(print #p`((2 + 3) * 5))
(print #p`(1 + 1 * np.exp(7)))

(setv x 5)
(print #p`(x + 2))

(print #p`(1 + 1 * np.exp(1e-15)))
;; note the real python syntax with commas.
;; also not the extra parens around 1e-5
(print #p`(1 + np.linspace((1e-5), 1, 5)))

; The 1e-5 gets mangled to 1e-5 in this example
; (print #p`(1 + np.linspace(1e-5, 1, 5)))

;; Here is the macro form. It is about as easy to write.
(print (py `(1 + np.linspace((1e-5), 1, 5))))
17
25
1097.63315843
7
2.0
[ 1.00001    1.2500075  1.500005   1.7500025  2.       ]
[ 1.00001    1.2500075  1.500005   1.7500025  2.       ]

Lots of things seem to work! Let's look into some other solutions that do not rely on the builtin eval.

2 Infix to prefix using code manipulation

This solution is inspired by https://sourceforge.net/p/readable/wiki/Solution/ , but probably isn't a full implementation. We will first develop a function to convert infix notation to prefix notation. This function is recursive to deal with nested expressions. So far it doesn't seem possible to recurse with macros (at least, I cannot figure out how to do it). We tangle this function to infix.hy so we can use it later.

It will have some limitations though:

  1. No operator precedence. We will use parentheses for precedence.
  2. Lisp syntax means 3+4 is not the same as 3 + 4. The first is interpreted as a name. So we will need spaces to separate everything.
(try
 (print (3+4))
 (except [e Exception]
   (print e)))

(print (+ 3 4))
name '3+4' is not defined
7

So, here is our infix function. Roughly, the function takes a CODE argument. If the CODE is iterable, it is a list of symbols, and we handle a few cases:

  • If it is a string, we return it.
  • if it has a length of one and is an expression we recurse on it, otherwise return the symbol.
  • if it has a length of two, we assume a unary operator and recurse on each element.
  • If there are three elements, we take the middle one as the operator, and switch it with the first element.
  • Otherwise we switch the first and second elements, and recurse on the rest of the list.
  • If it is not iterable we just return the element.

Two optional arguments provide some debug support to print what is happening.

(import [serialize [*]])

(defn nfx [code &optional [indent 0] [debug False]]
  "Transform the CODE expression to prefix notation.
We assume that CODE is in infix notation."
  (when debug (print (* " " indent) "code: " code " type: " (type code)))
  (cond
   [(coll? code)
    (cond

     ;; treat lists in [] special
     [(and (instance?  hy.models.list.HyList code)
           (not (instance?  hy.models.expression.HyExpression code)))
      (when debug (print "list: " code " type: " (type code)))
      code]

     [(= 1 (len code))
      ;; element is an Expression
      (when debug (print (* " " indent) "1: " code))
      (if (isinstance (car code) hy.models.expression.HyExpression)
        (nfx (car code) (+ indent 1) debug)
        ;; single element
        (car code))]

     ;; {- 1} ->  (- 1)
     [(= 2 (len code))
      (when debug (print (* " " indent) "2: " code))
      `(~(nfx (get code 0) (+ indent 1) debug)
         ~(nfx (get code 1) (+ indent 1) debug))]

     ;; {1 + 2} -> (+ 1 2)
     [(= 3 (len code))
      (when debug (print (* " " indent) "3: " code))
      `(~(get code 1)
         ~(nfx (get code 0) (+ indent 1) debug)
         ~(nfx (get code 2) (+ indent 1) debug))]

     ;; longer expression, swap first two and take the rest.
     [true
      (when debug (print "expr: " code))
      `(~(nfx (get code 1) (+ indent 1) debug)
         ~(nfx (get code 0) (+ indent 1) debug)
         (~@(nfx (cut code 2) (+ indent 1) debug)))])]

   ;; non-iterable just gets returned
   [true
    (when debug (print (* " " indent) "true: " code))
    code]))

Now, for some tests. First, an example with debug we can see what happens.

(import [infix [*]])
(print (nfx `(1 + (3 * 4)) :debug True))
 code:  (1L u'+' (3L u'*' 4L))  type:  <class 'hy.models.expression.HyExpression'>
 3:  (1L u'+' (3L u'*' 4L))
  code:  1  type:  <class 'hy.models.integer.HyInteger'>
  true:  1
  code:  (3L u'*' 4L)  type:  <class 'hy.models.expression.HyExpression'>
  3:  (3L u'*' 4L)
   code:  3  type:  <class 'hy.models.integer.HyInteger'>
   true:  3
   code:  4  type:  <class 'hy.models.integer.HyInteger'>
   true:  4
(u'+' 1L (u'*' 3L 4L))

You can see we return a list of symbols, and the result is not evaluated. Now for some more thorough tests. I use a little helper function here to show the input and output.

(import [infix [*]])
(import [serialize [stringify]])

(defn show [code]
  (print (.format "{0} -> {1}\n"
                  (stringify code)
                  (stringify (nfx code)))))

(show 1)
(show `(1))
(show `(- 1))
(show `((1)))
(show `(- (2 + 1)))

(show `(2 ** 4))
(show `(3 < 5))

(show `(1 + 3 * 5 + 6 - 9))
(show `((1 + (1 + 2)) * 5 + 6 - 9))
(show `(1 + 1 * (5 - 4)))
(show `(1 + 1 * (np.exp (17 - 10))))

; Note this one does not work right.
(show `(1 + (np.linspace 1e-5  1 5)))

(show `(x + long-name)) ; note name mangling occurs.

(show `(1 + 1 + 1 + 1 + 1))
1 -> 1

(1) -> 1

(- 1) -> (- 1)

((1)) -> 1

(- (2 + 1)) -> (- (+ 2 1))

(2 ** 4) -> (** 2 4)

(3 < 5) -> (< 3 5)

(1 + 3 * 5 + 6 - 9) -> (+ 1 (* 3 (+ 5 (- 6 9))))

((1 + (1 + 2)) * 5 + 6 - 9) -> (* (+ 1 (+ 1 2)) (+ 5 (- 6 9)))

(1 + 1 * (5 - 4)) -> (+ 1 (* 1 (- 5 4)))

(1 + 1 * (np.exp (17 - 10))) -> (+ 1 (* 1 (np.exp (- 17 10))))

(1 + (np.linspace 1e-05 1 5)) -> (+ 1 (1e-05 np.linspace (1 5)))

(x + long_name) -> (+ x long_name)

(1 + 1 + 1 + 1 + 1) -> (+ 1 (+ 1 (+ 1 (+ 1 1))))

Those all look reasonable I think. The last case could be simplified, but it would take some logic to make sure all the operators are the same, and that handles if any of the operands are expressions. We save that for later.

Now, we illustrate that the output code can be evaluated. Since we expand to code, we don't seem to have the namespace issues since the code is executed in our script.

(import [infix [*]])

(print (eval (nfx `(1 + 1 * (5 - 4)))))

(import [numpy :as np])
(print (eval (nfx `(1 + 1 * (np.exp (17 - 10))))))
2
1097.63315843

That syntax is not particularly nice, so next we build up a macro, and a new reader syntax. First, the macro.

(defmacro $ [&rest code]
  "Eval CODE in infix notation."
  `(do
    (import infix)
    (eval (infix.nfx ~code))))

Now we can use the simpler syntax here. It seems we still have quote the math to prevent it from being evaluated (which causes an error).

(import infix)
(require infix)

(print ($ `(1 + 1 * (5 - 4))))

(import [numpy :as np])
(print ($ `(1 + 1 * (np.exp (17 - 10)))))
2
1097.63315843

For the penultimate act, we introduce a new syntax for this. In the sweet expression syntax we would use {} for this, but this isn't currently possible for hylang, and is also used for dictionaries. We define a reader macro for this.

(defreader $ [code]
  (import infix)
  (infix.nfx code))

(defreader P [code]
  `(do (import infix)
       (eval (infix.nfx ~code))))
(import [infix [*]])
(require infix)

(import [numpy :as np])

(print #$(- 1))

(print #$(- (2 + 1)))

(print #$(2 ** 4))
(print #$(3 < 5))

(print #$(1 + 3 * 5 + 6 - 9))
(print #$((1 + (1 + 2)) * 5 + 6 - 9))
(print #$(1 + 1 * (5 - 4)))
(print #$(1 + 1 + 1 + 1 + 1))

;; we still have to be lispy with function calls (func args)
(print #$(1 + 1 * (np.exp (17 - 10))))

(setv a 3 t 6)
(print #$(a + t))

(setv long-a 5 long-b 6)
(print #$(long-a + long-b))

;; this fails because the linspace should not get unfixed. This is a bug in
;; our implementation

;; (print #P`(1 + (np.linspace 1e-5  1 5)))
-1
-3
16
True
7
8
2
5
1097.63315843
9
11

Mostly wonderful! We get variables passed through, and the name-mangling doesn't seem to matter. Note we don't have to quote this code. I think it is because in this reader macro we do not return code, but actually evaluate it I think. And somehow it works.

There is an issue with (print #$(1 + (np.linspace 1e-5 1 5))). The linspace call gets unfixed, which is wrong. There are some ways we could deal with that. One might be to only unfix known operators. Another might be some escape syntax that indicates not to unfix certain lists. For another day (TM).

(import [infix [*]])
(print (nfx `(1 + (np.linspace 1e-5  1 5)) :debug True))
 code:  (1L u'+' (u'np.linspace' 1e-05 1L 5L))  type:  <class 'hy.models.expression.HyExpression'>
 3:  (1L u'+' (u'np.linspace' 1e-05 1L 5L))
  code:  1  type:  <class 'hy.models.integer.HyInteger'>
  true:  1
  code:  (u'np.linspace' 1e-05 1L 5L)  type:  <class 'hy.models.expression.HyExpression'>
expr:  (u'np.linspace' 1e-05 1L 5L)
   code:  1e-05  type:  <class 'hy.models.float.HyFloat'>
   true:  1e-05
   code:  np.linspace  type:  <class 'hy.models.symbol.HySymbol'>
   true:  np.linspace
   code:  (1L 5L)  type:  <class 'hy.models.expression.HyExpression'>
   2:  (1L 5L)
    code:  1  type:  <class 'hy.models.integer.HyInteger'>
    true:  1
    code:  5  type:  <class 'hy.models.integer.HyInteger'>
    true:  5
(u'+' 1L (1e-05 u'np.linspace' (1L 5L)))

See, the linspace call is out of order.

3 The final test

For the final act, we use infix notation in a real problem we posed before.

3.1 with the string reader

We almost get way with exactly what we would have done in Python. The only thing was we had to put a space between -x to avoid a mangling issue that turned it into _x. I feel like that might be a fixable issue.

(import [numpy :as np])
(import [scipy.integrate [odeint]])
(import [scipy.special [jn]])
(import [matplotlib.pyplot :as plt])

(import [infix [*]])
(require infix)

(defn fbessel [Y x]
  "System of 1st order ODEs for the Bessel equation."
  (setv nu 0.0
        y (get Y 0)
        z (get Y 1))

  ;; define the derivatives
  (setv dydx z
        ;; the Python way is: "1.0 / x**2 * (-x * z - (x**2 - nu**2) * y)"
        dzdx (py `(1.0 / x**2 * (- x * z - (x**2 - nu**2) * y))))
  ;; Here is what it was with prefix notation
  ;; dzdx (* (/ 1.0 (** x 2)) (- (* (* -1 x) z) (* (- (** x 2) (** nu 2)) y))))
  ;; return derivatives
  [dydx dzdx])

(setv x0 1e-15
      y0 1.0
      z0 0.0
      Y0 [y0 z0])

(setv xspan (np.linspace 1e-15 10)
      sol (odeint fbessel Y0 xspan))

(plt.plot xspan (. sol [[Ellipsis 0]]) :label "Numerical solution")
(plt.plot xspan (jn 0 xspan) "r--" :label "Analytical solution")
(plt.legend :loc "best")

(plt.savefig "bessel-infix-s.png")

3.2 with #$ reader

This version is also somewhat close to the Python syntax, but it needs a lot more parentheses to get the right precedence, and spaces between almost everything for the lisp syntax, i.e. x**2 is a name, and (x ** 2) is the infix notation for exponentiation.

(import [numpy :as np])
(import [scipy.integrate [odeint]])
(import [scipy.special [jn]])
(import [matplotlib.pyplot :as plt])

(import [infix [*]])
(require infix)

(defn fbessel [Y x]
  "System of 1st order ODEs for the Bessel equation."
  (setv nu 0.0
        y (get Y 0)
        z (get Y 1))

  ;; define the derivatives
  (setv dydx z
        ;; the Python way is: "1.0 / x**2 * (-x * z - (x**2 - nu**2) * y)"
        dzdx #$((1.0 / (x ** 2)) * ((- x) * z) - (((x ** 2) - (nu ** 2)) * y)))
  ;; Here is what it was with prefix notation
  ;; dzdx (* (/ 1.0 (** x 2)) (- (* (* -1 x) z) (* (- (** x 2) (** nu 2)) y))))
  ;; return derivatives
  [dydx dzdx])

(setv x0 1e-15
      y0 1.0
      z0 0.0
      Y0 [y0 z0])

(setv xspan (np.linspace 1e-15 10)
      sol (odeint fbessel Y0 xspan))

(plt.plot xspan (. sol [[Ellipsis 0]]) :label "Numerical solution")
(plt.plot xspan (jn 0 xspan) "r--" :label "Analytical solution")
(plt.legend :loc "best")

(plt.savefig "bessel-infix.png")

That worked pretty well. This feels like an improvement for writing engineering programs in lisp!

Copyright (C) 2016 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter

Writing hy code from hy code

| categories: hylang | tags:

Here is one of the main reasons I am interested in a lisp for programming. I want to write programs that write programs. In Python, I have ended up doing things like this where we build up a script with string formatting and manipulation, write it to a file, and run it later or somewhere else. We need this because we run a lot of our calculations through a queue system which runs asynchronously from the work we do in an editor.

import os
for x in [1, 2, 3]:
    fname = 'p{0}.py'.format(x)

    program = '''#!/usr/bin/env python
def f(x):
    return x**{0}

import sys
print f(float(sys.argv[1]))'''.format(x)

    with open(fname, 'w') as f:
        f.write(program)

    os.chmod(fname, 0o755)

Then you can call these now at the command line like:

./p2.py 3
./p3.py 3
9.0
27.0

That is not too bad because the script is simple, but it is tedious to keep the indentation right, it is not always easy to keep track of the arguments (even with numbered indexes, names, etc… in the formatting), there is limited logic you can use in the arguments (e.g. no if/elif/elif/else, etc…), you lose all the value of having an editor in Python mode, so no syntax highlighting, eldoc, code completion, automatic indentation, etc… I don't like it, but it gets the job done.

Lisps allow you to treat code like data, in an editor in lisp-mode, so it should be ideal for this kind of thing. Here we look at getting that done with hy. For the simplest forms, we simply convert the code to a string, which can then be written to a file. You can see we probably got lucky here that the objects in the expression all print in a simple form that allows us to reconstruct the code. You can see here some aspects of Python peeking through the hy implementation. In data/quoted mode, the atoms in the list are not all simple symbols. By the time the program gets to running the code, they have been transformed to objects of various types that need to be handled separately.

(setv program `(+ 4 5))
(print (+ "(" (.join " " (list-comp (str x) [x program])) ")"))
(print (list-comp (type x) [x program]))
(+ 4 5)
[<class 'hy.models.symbol.HySymbol'>, <class 'hy.models.integer.HyInteger'>, <class 'hy.models.integer.HyInteger'>]

Real programs are not this simple, and we need to handle nested expressions and other types of objects. Consider this program. It has many different types in it, and they don't all get represented by the right syntax in print (i.e. with (repr object).

(let [program `(list {"a" 1 "b" 3} "b" 3 3.0 [1 1 2] :keyword (lambda [x] (* x 3)))]
  (print (list-comp (type x) [x program]))
  (for [x program] (print (.format "{0!r}" x))))
[<class 'hy.models.symbol.HySymbol'>, <class 'hy.models.dict.HyDict'>, <class 'hy.models.string.HyString'>, <class 'hy.models.integer.HyInteger'>, <class 'hy.models.float.HyFloat'>, <class 'hy.models.list.HyList'>, <class 'hy.models.keyword.HyKeyword'>, <class 'hy.models.expression.HyExpression'>]
u'list'
{u'a' 1L u'b' 3L}
u'b'
3L
3.0
[1L 1L 2L]
u'\ufdd0:keyword'
(u'lambda' [u'x'] (u'*' u'x' 3L))

Next we make a recursive expression to handle some of these. It is recursive to handle nested expressions. Here are the things in hy.models that might need special treatment. We make sure to wrap expressions in (), lists in [], dictionaries in {}, and strings in "". Keywords have a unicode character put in front of them, so we cut that off. Everything else seems to be ok to just convert to a string. This function gets tangled to serialize.hy so it can be used in subsequent code examples.

(import hy)

(defn stringify [form &optional debug]
  "Convert a FORM to a string."
  (when debug (print (.format "{0}: {1}" form (type form))))
  (cond
   [(isinstance form hy.models.expression.HyExpression)
    (+ "(" (.join " " (list-comp (stringify x debug) [x form])) ")")]
   [(isinstance form hy.models.dict.HyDict)
    (+ "{" (.join " " (list-comp (stringify x debug) [x form])) "}")]
   [(isinstance form hy.models.list.HyList)
    (+ "[" (.join " " (list-comp (stringify x debug) [x form])) "]")]
   [(isinstance form hy.models.symbol.HySymbol)
    (.format "{}" form)]
   [(isinstance form hy.models.keyword.HyKeyword)
    ;; these have some unicode prefix I want to remove
    (.format "{}" (cut form 1))]
   [(or (isinstance form hy.models.string.HyString)
        (isinstance form unicode))
    (.format "\"{}\"" form)]
   [true
    (.format "{}" form)]))

Now, some examples. These cover most of what I can imagine coming up.

(import [serialize [stringify]])  ;; tangled from the block above

;; some examples that cover most of what I am doing.
(print (stringify `(+ 5 6.0)))
(print (stringify `(defn f [x] (* 2 x))))
(print (stringify `(get {"a" 1 "b" 3} "b")))
(print (stringify `(print (+ 4 5 (* 6 7)))))
(print (stringify `(import [numpy :as np])))
(print (stringify `(import [scipy.optimize [fsolve]])))
(print (stringify `(set [2 2 3])))
(print (stringify `(complex 4 5)))
(print (stringify `(cons 4 5)))
(+ 5 6.0)
(defn f [x] (* 2 x))
(get {"a" 1 "b" 3} "b")
(print (+ 4 5 (* 6 7)))
(import [numpy :as np])
(import [scipy.optimize [fsolve]])
(set [2 2 3])
(complex 4 5)
(cons 4 5)

Those all look promising. Maybe it looks like nothing happened. Something did happen! We took code that was quoted (and hence like a list of data), and converted it into a string representation of the code. Now that we have a string form, we can do things like write it to a file.

Next, we add a function that can write that to an executable script.

(defn scriptify [form fname]
  (with [f (open fname "w")]
        (.write f "#!/usr/bin/env hy\n")
        (.write f (stringify form)))
  (import os)
  (os.chmod fname 0o755))

Here is an example

(import [serialize [stringify scriptify]])

;; make functions
(for [x (range 1 4)]
  (scriptify
   `(do
     (import sys)
     (defn f [x]
       (** x ~x))
     (print (f (float (get sys.argv 1)))))
   ;; fname to write to
   (.format "h{}.hy" x)))

Here is the proof those programs got created.

ls h[0-9].hy
echo
cat h1.hy
h1.hy
h2.hy
h3.hy

#!/usr/bin/env hy
(do (import sys) (defn f [x] (** x 1)) (print (f (float (get sys.argv 1)))))

The code is all on one line, which doesn't matter or hy. Yep, if it didn't occur to you, we could take those strings and send them over the internet so they could get executed remotely. They are one read-str and eval away from being lisp code again. Yes there are security concerns with that. And an amazing way to get something done.

(import [serialize [*]])
(print (eval (read-str (stringify `(+ 4 5)))))
9

We can run those programs at the command line:

hy h2.hy 10
hy h3.hy 10
100.0
1000.0

Now for a more realistic test. I make some scripts related to the kinds of molecular simulation we do. These scripts just setup a model of bulk Cu or Pt, and print the generated object. In a real application we would compute some thing from this object.

(import [serialize [stringify scriptify]])

(for [element ["Cu" "Pt"]]
  (scriptify `(do (import [ase.lattice [bulk]])
                  ;; we have to str the element to avoid a unicode error
                  ;; ase does not do unicode.
                  (setv atoms (bulk (str ~element) :a 4.5 :cubic True))
                  (print atoms))
             (.format "{}.hy" element)))

Here is what one of those scripts looks like

cat Pt.hy
#!/usr/bin/env hy
(do (import [ase.lattice [bulk]]) (setv atoms (bulk (str "Pt") :a 4.5 :cubic True)) (print atoms))

Note the comments are not in the generated script. These are evidently ignored in hy, and are not even elements. We can run this at the command line to. If this script did an actual calculation, we would have a mechanism to generate simulation scripts that run calculations and output the results we want!

hy Pt.hy
Atoms(symbols='Pt4', positions=..., cell=[4.5, 4.5, 4.5], pbc=[True, True, True])

So, we can write programs that write programs!

1 Serialize as compiled Python

It could be convenient to run the generated programs from Python instead of hy. Here we consider how to do that. I adapted this code from hy.importer.write_hy_as_pyc.

(import [hy.importer :as hi])
(import [hy._compat [PY3 PY33 MAGIC wr_long long_type]])
(import marshal)
(import os)

(defn hy2pyc [code fname]
  "Write CODE as Python compiled byte-code in FNAME."

  (setv program (stringify code))

  (setv _ast (hi.import_buffer_to_ast
              program
              "main"))

  (setv code (hi.ast_compile _ast "<string>" "exec"))

  ;; create file and close it so we get the size
  (with [f (open fname "wb")] nil)
  (with [f (open fname "wb")]
        (try
         (setv st (os.fstat (f.fileno)))
         (except [e AttributeError]
           (setv st (os.stat fname))))
        (setv timestamp (long_type (. st st_mtime))))
  (with [fc (open fname "wb")]
        (if PY3
          (.write fc b"\0\0\0\0") ; I amnot sure this is right in hy with b""
          (.write fc "\0\0\0\0"))
        (wr_long fc timestamp)
        (when PY33
          (wr_long fc st.st_size))
        (.dump marshal code fc)
        (.flush fc)
        (.seek fc 0 0)
        (.write fc MAGIC)))

Now for an example.

(import [serialize [*]])

(hy2pyc `(do
          (import sys)
          (defn f [x]
            (** x 3))
          (print (.format "Hy! {0}^3 is {1}."
                          (get sys.argv 1)
                          (f (float (get sys.argv 1))))))
          "main.pyc")

Now we can execute it like this.

python main.pyc 4
Hy! 4^3 is 64.0.

Well, that worked fine too!

2 Summary

In some ways this is similar to the string manipulation approach (they both generate programs after all), but there are these differences:

  1. We do not have the indentation issues of generating Python.
  2. The code is edited in hy-mode with full language support.
  3. Instead of formatting, and string replacements, you have to think of what is quoted and what is evaluated. I find that easier to think about than with strings.

There are some ways we could simplify this perhaps. In this post I added code to the built in python types so they could be represented as lisp code. We could add something like this to each of the hy.model objects so they natively can be represented as hy code. The repr functions on these should technically be used for that I think. On the other hand, this serialize code works fine, and lets me do what I want. It is pretty cool this is all possible!

Copyright (C) 2016 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter

Another step towards HyDE

| categories: hylang | tags:

(In case that isn't clear, it is a Python with a Lisp, and somewhat how I feel trying to see what this is all about ;)

I have been chipping away at HyDE, the Hy Development Environment. So far I have reasonable support for eldoc in hy code, and some integration into lispy.

The executive summary here is:

  1. We have a first approach at getting eldoc to work.
  2. We have better integration with lispy, including the inline describe and arg functionality, and jump to symbol.

You may want to just watch the video to see what it is about: https://www.youtube.com/watch?v=m62oiB6Feeo

The full details of these implementations are described at the end of this post. For now, we just load the functionality here:

(require 'mile-hy)
mile-hy

Some examples of usage:

(list (butlast [12 34 56]))
[12L, 34L]

For details of the implementations see the following discussion.

https://github.com/jkitchin/jmax/blob/master/mile-hy.el includes:

  • Setting up hy-mode with a repl (partly from lispy)
  • an eldoc function
  • some hooks for hy-mode to setup some functionality.
  • A hy src block expansion template for org-mode
  • the contents of what I previously called ob-hy.el

These things don't work without the code at https://github.com/jkitchin/hy/blob/hydoc/hy/core/hylp.hy which provides some hy functions to get eldoc strings, and file locations. These are still work in progress, but functional at this point.

I also adapted some parts of lispy to support hy better in my fork:

These are not fully ready to be integrated to lispy yet, as the functionality here depends on the hy code (in hylp.hy) that isn't part of hy yet. I hacked lispy anyway to see how easy it would be to extend it for hy. So far, it looks promising.

All of these put together lead to:

  1. eldoc support in hy code
  2. lispy support for C-1 descriptions and C-2 args inline.
  3. lispy support for M-. to jump to symbol definitions (although it is a tad hacky and uses hy to generate an org-link to open the code files at the line of the definition ;).

It is far from fully functional and there are some issues to resolve. The code will also probably change as I resolve some of those issues, but it works well enough to put some ideas out there. Feedback is welcome!

The eldoc functions work pretty well for the hy stuff. They don't work too well on the python side. The function at https://github.com/jkitchin/hy/blob/hydoc/hy/core/hylp.hy#L120 is where some improvement is needed. Right now it really only catches a few types of symbols.

For learning hylang a documentation sprint would be great.

  1. Add examples to the functions.
  2. Add documentation to the compiler @build definitions. Find a way to make this discoverable the way they are for functions and macros.
  3. Figure out how to get Python help in. It might be confusing because the syntax and examples will be different.

Copyright (C) 2016 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter

Getting hylp in hy

| categories: hylang | tags:

Hylang is a composite of hy functions, macros, compiler code, and Python. To me, this makes it critical to get to documentation and code easily to figure out what is happening. Here we look at how to get help.

I have hacked something called hydoc for hylang. This was a battle! There are functions, macros, and builtins that are defined in different places, and some things defined in hy, some in python, and some are done at compile time, … I found a lot of things, but there are still some corner cases I am sure. For some information, I resorted to parsing the source files myself to get arguments and file positions.

See the main code here: https://github.com/jkitchin/hy/blob/hydoc/hy/core/hylp.hy and the cmd-line script here: https://github.com/jkitchin/hy/blob/hydoc/bin/hydoc

It is the beginning of the HyDE, or Hy Development in Emacs. This is a precursor to getting eldoc working in Emacs for Hy. So, without further delay, here is an example command-line use. It is not too fast, but it works.

hydoc butlast
Usage: Usage: (butlast coll)

Returns coll except of last element.

[[/Users/jkitchin/Dropbox/python/hy/hy/core/language.hy::46]]

Yep, that is an org-mode link that jumps right to the source definition (in Emacs of course). We can also use it in hy. I have for now put this library (which contains functions and macros) in hy.core.hylp. It may not stay there.

(import [hy.core.hylp [*]])
(require hy.core.hylp)

(? "with")
Usage: (with args &rest body)

shorthand for nested with* loops:
  (with [x foo y bar] baz) ->
  (with* [x foo]
    (with* [y bar]
      baz))

[[/Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy::34]]

Compare that to:

(help butlast)
Help on function butlast in module hy.core.language:

butlast(coll)
    Returns coll except of last element.

pydoc/? is better because it works on macros too, and gives you more information, and in the form that you use in hy, e.g. (butlast coll) not butlast(coll).

I should point out, this is not in hy core anywhere by my github fork right now. It is still being developed. And it isn't perfect or comprehensive yet.

Let's see how good. How about we auto-generate some documentation? We will try to generate help for all the core language functions, shadowed functions, macros, and the compiler @build functions.

This is still hackier than I would like, but there is some tricky name-mangling in hy if there is a - in the name, e.g. what we use for minus, and also if there is a * in the name, it seems to get expanded. I still don't understand why I need to eval all of this here, but it works, and I get an error about no attribute named key if I don't. It seems to have some consequences though of turning some things into Python objects (especially itertools). It is good enough to share for now. Maybe someone will have a good idea ;)

Here is the code that generates the docs with (in org-mode) links to the source! The output follows, and is pretty long. The nice thing about this is the docs are generated, so we can update them pretty readily with new versions.

One thing that stands out is the lack of documentation on the compiler defined things. It might be worth figuring out how to put documentation on them, perhaps as an optional argument to the build decorator?

(import [hy.core.hylp [*]])
(require hy.core.hylp)

(print "*** hy version " (. hy __version__))
(print "**** Language")
(for [key (sorted (hy-language-keywords))]
  (print "***** " key)
  (print (eval `(? ~(string key)))))

(print "**** Shadowed")
(for [key (sorted (hy-shadow-keywords))]
  (print "***** " key)
  (print (eval `(? ~(string key)))))

(print "**** Macros")
(for [key (sorted (hy-macro-keywords))]
  (print "***** " key)
  (print (eval `(? ~(string key)))))

(print "**** Compiler functions")
(for [key (sorted (hy-compiler-keywords))]
  (print "***** " key)
  (print (eval `(? ~(string key)))))

1 hy version 0.11.0

1.1 Language

  1. *map

    Usage: (*map unknown args)

    starmap(function, sequence) –> starmap object

    Return an iterator whose values are returned from the function evaluated with a argument tuple taken from the given sequence.

    no code::-1

  2. accumulate

    Usage: (accumulate iterable &optional [func operator.add])

    accumulate(iterable[, func]) –> accumulate object

    Return series of accumulated sums (or other binary function results).

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  3. butlast

    Usage: (butlast coll)

    Returns coll except of last element.

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  4. calling_module_name

    Usage: (calling_module_name &optional [n 1])

    Get the name of the module calling `n` levels up the stack from the `calling-module-name` function call (by default, one level up)

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  5. chain

    Usage: (chain unknown args)

    chain(*iterables) –> chain object

    Return a chain object whose .next() method returns elements from the first iterable until it is exhausted, then elements from the next iterable, until all of the iterables are exhausted.

    no code::-1

  6. combinations

    Usage: (combinations unknown args)

    combinations(iterable, r) –> combinations object

    Return successive r-length combinations of elements in the iterable.

    combinations(range(4), 3) –> (0,1,2), (0,1,3), (0,2,3), (1,2,3)

    no code::-1

  7. compress

    Usage: (compress unknown args)

    compress(data, selectors) –> iterator over selected data

    Return data elements corresponding to true selector elements. Forms a shorter iterator from selected data elements using the selectors to choose the data elements.

    no code::-1

  8. cons

    Usage: (cons a b)

    Return a fresh cons cell with car = a and cdr = b

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  9. count

    Usage: (count unknown args)

    count(start=0, step=1) –> count object

    Return a count object whose .next() method returns consecutive values. Equivalent to:

    def count(firstval=0, step=1): x = firstval while 1: yield x x += step

    no code::-1

  10. cycle

    Usage: (cycle unknown args)

    cycle(iterable) –> cycle object

    Return elements from the iterable until it is exhausted. Then repeat the sequence indefinitely.

    no code::-1

  11. dec
  12. disassemble

    Usage: (disassemble tree &optional [codegen false])

    Return the python AST for a quoted Hy tree as a string. If the second argument is true, generate python code instead.

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  13. distinct

    Usage: (distinct coll)

    Return a generator from the original collection with duplicates removed

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  14. drop

    Usage: (drop count coll)

    Drop `count` elements from `coll` and yield back the rest

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  15. drop_last

    Usage: (drop_last n coll)

    Return a sequence of all but the last n elements in coll.

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  16. drop_while

    Usage: (drop_while unknown args)

    dropwhile(predicate, iterable) –> dropwhile object

    Drop items from the iterable while predicate(item) is true. Afterwards, return every element until the iterable is exhausted.

    no code::-1

  17. filter

    Usage: (filter unknown args)

    ifilter(function or None, sequence) –> ifilter object

    Return those items of sequence for which function(item) is true. If function is None, return the items that are true.

    no code::-1

  18. first

    Usage: (first coll)

    Return first item from `coll`

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  19. flatten

    Usage: (flatten coll)

    Return a single flat list expanding all members of coll

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  20. fraction

    Usage: (fraction unknown args)

    This class implements rational numbers.

    In the two-argument form of the constructor, Fraction(8, 6) will produce a rational number equivalent to 4/3. Both arguments must be Rational. The numerator defaults to 0 and the denominator defaults to 1 so that Fraction(3) = 3 and Fraction() = 0.

    Fractions can also be constructed from:

    • numeric strings similar to those accepted by the float constructor (for example, '-2.3' or '1e10')
    • strings of the form '123/456'
    • float and Decimal instances
    • other Rational instances (including integers)

    no code::-1

  21. gensym

    Usage: (gensym &optional [g "G"])

    None

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  22. group_by

    Usage: (group_by unknown args)

    groupby(iterable[, keyfunc]) -> create an iterator which returns (key, sub-iterator) grouped by each value of key(value).

    no code::-1

  23. identity

    Usage: (identity x)

    Returns the argument unchanged

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  24. inc
  25. input

    Usage: (input unknown args)

    raw_input([prompt]) -> string

    Read a string from standard input. The trailing newline is stripped. If the user hits EOF (Unix: Ctl-D, Windows: Ctl-Z+Return), raise EOFError. On Unix, GNU readline is used if enabled. The prompt string, if given, is printed without a trailing newline before reading.

    no code::-1

  26. integer

    Usage: (integer x)

    Return Hy kind of integer

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  27. interleave

    Usage: (interleave &rest seqs)

    Return an iterable of the first item in each of seqs, then the second etc.

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  28. interpose

    Usage: (interpose item seq)

    Return an iterable of the elements of seq separated by item

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  29. is_coll

    Usage: (is_coll coll)

    Checks whether item is a collection

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  30. is_cons

    Usage: (is_cons c)

    Check whether c can be used as a cons object

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  31. is_empty

    Usage: (is_empty coll)

    Return True if `coll` is empty

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  32. is_even

    Usage: (is_even n)

    Return true if n is an even number

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  33. is_every

    Usage: (is_every pred coll)

    Return true if (pred x) is logical true for every x in coll, else false

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  34. is_float

    Usage: (is_float x)

    Return True if x is float

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  35. is_instance
  36. is_integer

    Usage: (is_integer x)

    Return True if x in an integer

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  37. is_integer_char

    Usage: (is_integer_char x)

    Return True if char `x` parses as an integer

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  38. is_iterable

    Usage: (is_iterable x)

    Return true if x is iterable

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  39. is_iterator

    Usage: (is_iterator x)

    Return true if x is an iterator

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  40. is_keyword

    Usage: (is_keyword k)

    Check whether k is a keyword

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  41. is_neg

    Usage: (is_neg n)

    Return true if n is < 0

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  42. is_nil

    Usage: (is_nil x)

    Return true if x is nil (None)

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  43. is_none

    Usage: (is_none x)

    Return true if x is None

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  44. is_numeric
  45. is_odd

    Usage: (is_odd n)

    Return true if n is an odd number

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  46. is_pos

    Usage: (is_pos n)

    Return true if n is > 0

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  47. is_string

    Usage: (is_string x)

    Return True if x is a string

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  48. is_symbol

    Usage: (is_symbol s)

    Check whether s is a symbol

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  49. is_zero

    Usage: (is_zero n)

    Return true if n is 0

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  50. islice

    Usage: (islice unknown args)

    islice(iterable, [start,] stop [, step]) –> islice object

    Return an iterator whose next() method returns selected values from an iterable. If start is specified, will skip all preceding elements; otherwise, start defaults to zero. Step defaults to one. If specified as another value, step determines how many values are skipped between successive calls. Works like a slice() on a list but returns an iterator.

    no code::-1

  51. iterate
  52. keyword

    Usage: (keyword value)

    Create a keyword from the given value. Strings numbers and even objects with the name magic will work

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  53. last

    Usage: (last coll)

    Return last item from `coll`

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  54. list*

    Usage: (list* hd &rest tl)

    Return a dotted list construed from the elements of the argument

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  55. macroexpand

    Usage: (macroexpand form)

    Return the full macro expansion of form

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  56. macroexpand_1

    Usage: (macroexpand_1 form)

    Return the single step macro expansion of form

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  57. map

    Usage: (map unknown args)

    imap(func, *iterables) –> imap object

    Make an iterator that computes the function using arguments from each of the iterables. Like map() except that it returns an iterator instead of a list and that it stops when the shortest iterable is exhausted instead of filling in None for shorter iterables.

    no code::-1

  58. merge_with

    Usage: (merge_with f &rest maps)

    Returns a map that consists of the rest of the maps joined onto the first. If a key occurs in more than one map, the mapping(s) from the latter (left-to-right) will be combined with the mapping in the result by calling (f val-in-result val-in-latter).

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  59. multicombinations

    Usage: (multicombinations unknown args)

    combinations_with_replacement(iterable, r) –> combinations_with_replacement object

    Return successive r-length combinations of elements in the iterable allowing individual elements to have successive repeats. combinations_with_replacement('ABC', 2) –> AA AB AC BB BC CC

    no code::-1

  60. name

    Usage: (name value)

    Convert the given value to a string. Keyword special character will be stripped. String will be used as is. Even objects with the name magic will work

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  61. nth

    Usage: (nth coll n &optional [default nil])

    Return nth item in collection or sequence, counting from 0. Return nil if out of bounds unless specified otherwise.

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  62. partition

    Usage: (partition coll &optional [n 2] step [fillvalue -sentinel])

    Chunks coll into n-tuples (pairs by default). The remainder, if any, is not included unless a fillvalue is specified. The step defaults to n, but can be more to skip elements, or less for a sliding window with overlap.

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  63. permutations

    Usage: (permutations unknown args)

    permutations(iterable[, r]) –> permutations object

    Return successive r-length permutations of elements in the iterable.

    permutations(range(3), 2) –> (0,1), (0,2), (1,0), (1,2), (2,0), (2,1)

    no code::-1

  64. product

    Usage: (product unknown args)

    product(*iterables) –> product object

    Cartesian product of input iterables. Equivalent to nested for-loops.

    For example, product(A, B) returns the same as: ((x,y) for x in A for y in B). The leftmost iterators are in the outermost for-loop, so the output tuples cycle in a manner similar to an odometer (with the rightmost element changing on every iteration).

    To compute the product of an iterable with itself, specify the number of repetitions with the optional repeat keyword argument. For example, product(A, repeat=4) means the same as product(A, A, A, A).

    product('ab', range(3)) –> ('a',0) ('a',1) ('a',2) ('b',0) ('b',1) ('b',2) product((0,1), (0,1), (0,1)) –> (0,0,0) (0,0,1) (0,1,0) (0,1,1) (1,0,0) …

    no code::-1

  65. range

    Usage: (range unknown args)

    xrange(stop) -> xrange object xrange(start, stop[, step]) -> xrange object

    Like range(), but instead of returning a list, returns an object that generates the numbers in the range on demand. For looping, this is slightly faster than range() and more memory efficient.

    no code::-1

  66. read

    Usage: (read &optional [from-file sys.stdin] [eof ""])

    Read from input and returns a tokenized string. Can take a given input buffer to read from

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  67. read_str

    Usage: (read_str input)

    Reads and tokenizes first line of input

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  68. reduce

    Usage: (reduce unknown args)

    reduce(function, sequence[, initial]) -> value

    Apply a function of two arguments cumulatively to the items of a sequence, from left to right, so as to reduce the sequence to a single value. For example, reduce(lambda x, y: x+y, [1, 2, 3, 4, 5]) calculates ((((1+2)+3)+4)+5). If initial is present, it is placed before the items of the sequence in the calculation, and serves as a default when the sequence is empty.

    no code::-1

  69. remove

    Usage: (remove unknown args)

    ifilterfalse(function or None, sequence) –> ifilterfalse object

    Return those items of sequence for which function(item) is false. If function is None, return the items that are false.

    no code::-1

  70. repeat

    Usage: (repeat unknown args)

    repeat(object [,times]) -> create an iterator which returns the object for the specified number of times. If not specified, returns the object endlessly.

    no code::-1

  71. repeatedly

    Usage: (repeatedly func)

    Yield result of running func repeatedly

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  72. rest

    Usage: (rest coll)

    Get all the elements of a coll, except the first.

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  73. second

    Usage: (second coll)

    Return second item from `coll`

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  74. some

    Usage: (some pred coll)

    Return the first logical true value of (pred x) for any x in coll, else nil

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  75. string

    Usage: (string x)

    Cast x as current string implementation

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  76. take

    Usage: (take count coll)

    Take `count` elements from `coll`, or the whole set if the total number of entries in `coll` is less than `count`.

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  77. take_nth

    Usage: (take_nth n coll)

    Return every nth member of coll raises ValueError for (not (pos? n))

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  78. take_while

    Usage: (take_while unknown args)

    takewhile(predicate, iterable) –> takewhile object

    Return successive entries from an iterable as long as the predicate evaluates to true for each entry.

    no code::-1

  79. tee

    Usage: (tee unknown args)

    tee(iterable, n=2) –> tuple of n independent iterators.

    no code::-1

  80. xor

    Usage: (xor a b)

    Perform exclusive or between two parameters

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/language.hy

  81. zip

    Usage: (zip unknown args)

    izip(iter1 [,iter2 […]]) –> izip object

    Return a izip object whose .next() method returns a tuple where the i-th element comes from the i-th iterable argument. The .next() method continues until the shortest iterable in the argument sequence is exhausted and then it raises StopIteration. Works like the zip() function but consumes less memory by returning an iterator instead of a list.

    no code::-1

  82. zip_longest

    Usage: (zip_longest unknown args)

    izip_longest(iter1 [,iter2 […]], [fillvalue=None]) –> izip_longest object

    Return an izip_longest object whose .next() method returns a tuple where the i-th element comes from the i-th iterable argument. The .next() method continues until the longest iterable in the argument sequence is exhausted and then it raises StopIteration. When the shorter iterables are exhausted, the fillvalue is substituted in their place. The fillvalue defaults to None or can be specified by a keyword argument.

    no code::-1

1.2 Shadowed

  1. !=

    Usage: (!= &rest args)

    Shadow != operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  2. *

    Usage: (* &rest args)

    Shadow * operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  3. +

    Usage: (+ &rest args)

    Shadow + operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  4. -

    Usage: (- &rest args)

    Shadow - operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  5. /

    Usage: (/ &rest args)

    Shadow / operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  6. <

    Usage: (< &rest args)

    Shadow < operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  7. <=

    Usage: (<= &rest args)

    Shadow <= operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  8. =

    Usage: (= &rest args)

    Shadow = operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  9. >

    Usage: (> &rest args)

    Shadow > operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  10. >=

    Usage: (>= &rest args)

    Shadow >= operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

1.3 Macros

  1. ?

    Usage: (? sym)

    Return help for SYM which is a string.

    hylp.hy

  2. _>

    Usage: (_> head &rest rest)

    Threads the head through the rest of the forms. Inserts head as the second item in the first form of rest. If there are more forms, inserts the first form as the second item in the second form of rest, etc.

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  3. _>>

    Usage: (_>> head &rest rest)

    Threads the head through the rest of the forms. Inserts head as the last item in the first form of rest. If there are more forms, inserts the first form as the last item in the second form of rest, etc.

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  4. car

    Usage: (car thing)

    Get the first element of a list/cons

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  5. cdr

    Usage: (cdr thing)

    Get all the elements of a thing, except the first

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  6. cond

    Usage: (cond &rest branches)

    shorthand for nested ifs: (cond [foo bar] [baz quux]) -> (if foo bar (if baz quux))

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  7. defmacro/g_bang

    Usage: (defmacro/g_bang name args &rest body)

    None

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  8. defmain

    Usage: (defmain args &rest body)

    Write a function named "main" and do the if main dance

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  9. defn

    Usage: (defn name lambda-list &rest body)

    define a function `name` with signature `lambda-list` and body `body`

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/bootstrap.hy

  10. doto

    Usage: (doto form &rest expressions)

    Performs a sequence of potentially mutating actions on an initial object, returning the resulting object

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  11. for

    Usage: (for args &rest body)

    shorthand for nested for loops: (for [x foo y bar] baz) -> (for* [x foo] (for* [y bar] baz))

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  12. hylp_info

    Usage: (hylp_info sym)

    Return Usage, docstring filename, lineno for the string SYM.

    hylp.hy

  13. if
  14. if_not

    Usage: (if_not test not-branch &optional yes-branch)

    Like `if`, but execute the first branch when the test fails

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  15. if_python2

    Usage: (if_python2 python2-form python3-form)

    If running on python2, execute python2-form, else, execute python3-form

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/bootstrap.hy

  16. let

    Usage: (let variables &rest body)

    Execute `body` in the lexical context of `variables`

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/bootstrap.hy

  17. lif

    Usage: (lif &rest args)

    Like `if`, but anything that is not None/nil is considered true.

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  18. lif_not

    Usage: (lif_not test not-branch &optional yes-branch)

    Like `if-not`, but anything that is not None/nil is considered true.

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  19. macro_error

    Usage: (macro_error location reason)

    error out properly within a macro

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/bootstrap.hy

  20. unless

    Usage: (unless test &rest body)

    Execute `body` when `test` is false

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  21. when

    Usage: (when test &rest body)

    Execute `body` when `test` is true

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  22. with

    Usage: (with args &rest body)

    shorthand for nested with* loops: (with [x foo y bar] baz) -> (with* [x foo] (with* [y bar] baz))

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  23. with_gensyms

    Usage: (with_gensyms args &rest body)

    None

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/macros.hy

  24. yield_from

1.4 Compiler functions

  1. !=

    Usage: (!= &rest args)

    Shadow != operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  2. %

    Usage: % defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  3. %=

    Usage: %= defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  4. &

    Usage: & defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  5. &=

    Usage: &= defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  6. *

    Usage: (* &rest args)

    Shadow * operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  7. **

    Usage: ** defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  8. **=

    Usage: **= defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  9. *=

    Usage: *= defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  10. +

    Usage: (+ &rest args)

    Shadow + operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  11. +=

    Usage: += defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  12. ,

    Usage: , defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  13. -

    Usage: (- &rest args)

    Shadow - operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  14. .

    Usage: . defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  15. /

    Usage: (/ &rest args)

    Shadow / operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  16. //

    Usage: // defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  17. //=

    Usage: //= defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  18. /=

    Usage: /= defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  19. <

    Usage: (< &rest args)

    Shadow < operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  20. <<

    Usage: << defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  21. <<=

    Usage: <<= defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  22. <=

    Usage: (<= &rest args)

    Shadow <= operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  23. =

    Usage: (= &rest args)

    Shadow = operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  24. >

    Usage: (> &rest args)

    Shadow > operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  25. >=

    Usage: (>= &rest args)

    Shadow >= operator for when we need to import / map it against something

    file:///Users/jkitchin/Dropbox/python/hy/hy/core/shadow.hy

  26. >>

    Usage: >> defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  27. >>=

    Usage: >>= defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  28. @

    Usage: @ defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  29. @=

    Usage: @= defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  30. ^

    Usage: ^ defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  31. ^=

    Usage: ^= defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  32. _=

    Usage: _= defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  33. and

    Usage: and defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  34. apply

    Usage: apply defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  35. assert

    Usage: assert defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  36. assoc

    Usage: assoc defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  37. break

    Usage: break defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  38. continue

    Usage: continue defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  39. cut

    Usage: cut defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  40. def

    Usage: def defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  41. defclass

    Usage: defclass defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  42. defmacro

    Usage: defmacro defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  43. defreader

    Usage: defreader defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  44. del

    Usage: del defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  45. dict_comp

    Usage: dict_comp defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  46. dispatch_reader_macro

    Usage: dispatch_reader_macro defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  47. do

    Usage: do defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  48. eval

    Usage: eval defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  49. eval_and_compile

    Usage: eval_and_compile defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  50. eval_when_compile

    Usage: eval_when_compile defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  51. except

    Usage: except defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  52. fn

    Usage: fn defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  53. for*

    Usage: for* defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  54. genexpr

    Usage: genexpr defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  55. get

    Usage: get defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  56. global

    Usage: global defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  57. if*

    Usage: if* defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  58. import

    Usage: import defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  59. in

    Usage: in defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  60. is

    Usage: is defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  61. is_not

    Usage: is_not defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  62. lambda

    Usage: lambda defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  63. list_comp

    Usage: list_comp defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  64. nonlocal

    Usage: nonlocal defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  65. not

    Usage: not defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  66. not_in

    Usage: not_in defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  67. or

    Usage: or defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  68. quasiquote

    Usage: quasiquote defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  69. quote

    Usage: quote defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  70. raise

    Usage: raise defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  71. require

    Usage: require defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  72. set_comp

    Usage: set_comp defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  73. setv

    Usage: setv defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  74. try

    Usage: try defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  75. unquote

    Usage: unquote defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  76. unquote_splicing

    Usage: unquote_splicing defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  77. while

    Usage: while defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  78. with*

    Usage: with* defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  79. with_decorator

    Usage: with_decorator defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  80. yield

    Usage: yield defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  81. yield_from
  82. |

    Usage: | defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  83. |=

    Usage: |= defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

  84. ~

    Usage: ~ defined in hy/compiler

    No docstring available.

    file:///Users/jkitchin/Dropbox/python/hy/hy/compiler.py

Copyright (C) 2016 by John Kitchin. See the License for information about copying.

org-mode source

Org-mode version = 8.2.10

Discuss on Twitter
« Previous Page -- Next Page »