Add one-argument division and rationals (closes #825 and #826)

This commit is contained in:
Ryan Gonzalez 2015-06-26 16:10:22 -05:00
parent f1c315da24
commit 016d25d104
7 changed files with 56 additions and 10 deletions

View File

@ -207,6 +207,26 @@ Returns ``True`` if *x* is a float.
False
.. _fraction-fn:
fraction
--------
Returns a Python object of type ``fractions.Fraction``.
.. code-block:: hy
=> (fraction 1 2)
Fraction(1, 2)
Note that Hy has a built-in fraction literal that does the same thing:
.. code-block:: hy
=> 1/2
Fraction(1, 2)
.. _even?-fn:
even?

View File

@ -200,6 +200,10 @@ Hy. Let's experiment with this in the hy interpreter::
(1, 2, 3)
=> #{3 1 2}
{1, 2, 3}
=> 1/2
Fraction(1, 2)
Notice the last two lines: Hy has a fraction literal like Clojure.
If you are familiar with other Lisps, you may be interested that Hy
supports the Common Lisp method of quoting:

View File

@ -1721,8 +1721,6 @@ class HyASTCompiler(object):
col_offset=e.start_column)
@builds("%")
@builds("/")
@builds("//")
@builds("**")
@builds("<<")
@builds(">>")
@ -1764,11 +1762,14 @@ class HyASTCompiler(object):
@builds("+")
@builds("*")
@builds("/")
@builds("//")
def compile_maths_expression_mul(self, expression):
if len(expression) > 2:
return self.compile_maths_expression(expression)
else:
id_op = {"+": HyInteger(0), "*": HyInteger(1)}
id_op = {"+": HyInteger(0), "*": HyInteger(1), "/": HyInteger(1),
"//": HyInteger(1)}
op = expression.pop(0)
arg = expression.pop(0) if expression else id_op[op]

View File

@ -26,6 +26,7 @@
(import itertools)
(import functools)
(import collections)
(import [fractions [Fraction :as fraction]])
(import sys)
(import [hy._compat [long-type]]) ; long for python2, int for python3
(import [hy.models.cons [HyCons]]
@ -418,10 +419,10 @@
(def *exports* '[Botsbuildbots
butlast calling-module-name coll? cons cons? cycle
dec distinct disassemble drop drop-last drop-while empty? even?
every? first filter filterfalse flatten float? gensym identity
inc input instance? integer integer? integer-char? interleave
interpose iterable? iterate iterator? keyword keyword? last list*
macroexpand macroexpand-1 map merge-with name neg? nil? none?
nth numeric? odd? pos? range read remove repeat repeatedly
rest reduce second some string string? symbol? take take-nth
take-while zero? zip zip_longest zipwith])
every? first filter filterfalse flatten float? fraction gensym
identity inc input instance? integer integer? integer-char?
interleave interpose iterable? iterate iterator? keyword
keyword? last list* macroexpand macroexpand-1 map merge-with
name neg? nil? none? nth numeric? odd? pos? range read remove
repeat repeatedly rest reduce second some string string?
symbol? take take-nth take-while zero? zip zip_longest zipwith])

View File

@ -266,6 +266,14 @@ def t_identifier(p):
except ValueError:
pass
if '/' in obj:
try:
lhs, rhs = obj.split('/')
return HyExpression([HySymbol('fraction'), HyInteger(lhs),
HyInteger(rhs)])
except ValueError:
pass
try:
return HyFloat(obj)
except ValueError:

View File

@ -108,6 +108,13 @@ def test_lex_integers():
assert objs == [HyInteger(42)]
def test_lex_fractions():
""" Make sure that fractions are valid expressions"""
objs = tokenize("1/2")
assert objs == [HyExpression([HySymbol("fraction"), HyInteger(1),
HyInteger(2)])]
def test_lex_expression_float():
""" Make sure expressions can produce floats """
objs = tokenize("(foo 2.)")

View File

@ -12,6 +12,11 @@
(assert (isinstance sys.argv list)))
(defn test-fractions []
"NATIVE: test fractions"
(assert (= 1/2 (fraction 1 2))))
(defn test-lists []
"NATIVE: test lists work right"
(assert (= [1 2 3 4] (+ [1 2] [3 4]))))