The Racket Multi-Paradigm Translator is a tool designed to convert Racket code into Python code. Racket is a functional programming language that supports multiple paradigms, including functional, imperative, and logic programming. This translator focuses on converting Racket's functional constructs into Python's equivalent functional paradigm, using constructs like map
, filter
, and comprehensions to replace traditional loops like while
and for
.
This translator employs AI technologies to generate parse tree graphs for visualizing the abstract syntax trees (ASTs) of Racket code. These parse tree graphs aid in understanding the structure and behavior of the code during the translation process.
The Translator focus on declarative Python, avoiding traditional imperative constructs - look at functions examples - .
- Interpreter Mode: Allows users to run the translator in an interactive mode.
- Usage:
- On Unix (Linux/Mac):
python3 -m racket-to-python-translator
- On Windows:
python -m racket-to-python-translator
- On Unix (Linux/Mac):
- Usage:
- AI-powered Parse Tree Generation: Utilizes AI technologies from
google.generativeai
andgraphviz
to generate parse tree graphs for visualizing the abstract syntax trees (ASTs) of Racket code. These parse tree graphs aid in understanding the structure and behavior of the code during the translation process. - File Translation: Translates a specific Racket file.
- Usage:
python -m racket-to-python-translator file_name.rkt
- Usage:
- Unit Testing: Supports running unit tests to verify translation accuracy.
- Usage:
python -m racket-to-python-translator/tests/test_name.py
- Usage:
- Racket:
(define x 10)
- Racket Grammar:
(define <variable> <value>)
- Python:
x = 10
- Racket:
; comment (+ 1 2 3) (define y (+ x 1)) (max 3 -2 4.1 1/3) (sqrt 9/4) (abs -5) (display "I'm Racket. Nice to meet you!\n") (writeln (sum-of-squares x y)) ; output: 25
- Python:
# comment add_all((1, 2, 3)) y = all_add((x, 1)) max(3, -2, 4.1, 1/3) math.sqrt(9/4) abs(-5) print("I'm Racket. Nice to meet you!\n") print(sum_of_squares(x, y)) # output: 25
- Racket:
(let ([x 3][y (+ x 1)])(y))
- Python:
print((y:=x + 1))
(Declarative is used)
-
Racket (declarative):
(define square (lambda (x) (* x x))) (square 5) (display ((lambda (x) (* x x)) 5))
-
Python (declarative):
square = lambda x: x * x print(square(5)) print((lambda x: x * x)(5))
-
Python (imperative):
def square(x): return x * x print(square(5))
-
Racket (functional):
(map (lambda (x) (* x 2)) '(1 2 3 4 5))
-
Python (functional):
squared_numbers = list(map(lambda x: x * 2, [1, 2, 3, 4, 5]))
-
Python (imperative):
def square(x): return x * x numbers = [1, 2, 3, 4, 5] squared_numbers = [] for num in numbers: squared_numbers.append(square(num)) print(squared_numbers) # Output: [1, 4, 9, 16, 25]
-
Racket (functional):
(display (filter (lambda (x) (= (even? x) 0)) '(1 2 3 4 5)))
-
Python (functional):
even_numbers = list(filter(lambda x: x % 2 == 0, [1, 2, 3, 4, 5]))
-
Python (imperative):
numbers = [1, 2, 3, 4, 5] even_numbers = [] for num in numbers: if num % 2 == 0: even_numbers.append(num) print(even_numbers) # Output: [2, 4]
-
Racket (functional):
(display (foldl (lambda (x y) (+ x y)) 0 '(1 2 3 4 5))) ; Output: 15
-
Python (functional):
from functools import reduce total_sum = reduce(lambda x, y: x + y, [1, 2, 3, 4, 5]) print(total_sum) # Output: 15
-
Python (imperative):
numbers = [1, 2, 3, 4, 5] total_sum = 0 for num in numbers: total_sum += num print(total_sum) # Output: 15
- Racket:
(if (> x 0) 'positive 'non-positive')
- Python:
'positive' if x > 0 else 'non-positive'
- Racket:
(define (example x) (cond [(< x 0) 'negative'] [(= x 0) 'zero'] [(> x 0) 'positive']))
- Python:
example = lambda x: ( 'negative' if x < 0 else ('zero' if x == 0 else ('positive' if x > 0 else None))
- Racket:
(define (fact-helper n acc) (cond [(= n 1) acc] [else (fact-helper (- n 1) (* n acc))])) (define (fact n) (fact-helper n 1))
- Python:
fact_helper = lambda n, acc: acc if n == 1 else fact_helper(n - 1, n * acc) fact = lambda n: fact_helper(n, 1)
- Racket:
(define sum_ (lambda (x y) (+ x y))) (sum_ 5 3)
- Python:
sum_ = lambda x, y: add_all((x, y)) print(sum_(5, 3))
- Racket:
(map (lambda (x) (* x 2)) '(1 2 3 4 5))
- Python:
list(map(lambda x: mul_all(x, x), [1, 2, 3, 4, 5]))
- Racket:
(foldl + 0 '(1 2 3 4 5))
- Python:
from functools import reduce reduce(lambda x, y: x + y, [1, 2, 3, 4, 5])
- Turing Complete: The subset of Racket supported by this translator is Turing complete, meaning it can compute anything that is computable.
- Practical Applications: The translator can be used for practical applications such as matrix multiplication, computer vision, image processing, and solving LeetCode problems.
<program> ::= <expression> | <expression> <program>
<expression> ::= <define> | <function> | <if> | <for> | <map> | <lambda> | <let> | <begin>
<define> ::= "(define" <variable> <value> ")"
<function> ::= "(define" "(" <function-name> <parameters> ")" <body> ")"
<parameters> ::= <variable> | <variable> <parameters>
<body> ::= <expression> | <expression> <body>
<if> ::= "(if" <condition> <then-branch> <else-branch> ")"
<condition> ::= <expression>
<then-branch> ::= <expression>
<else-branch> ::= <expression>
<for> ::= "(for" "(" "[" <variable> "(" "in-range" <start> <end> ")" "]" ")" <body> ")"
<start> ::= <number> | <variable>
<end> ::= <number> | <variable>
<map> ::= "(map" <function> <list> ")"
<list> ::= "'" "(" <elements> ")"
<elements> ::= <value> | <value> <elements>
<lambda> ::= "(lambda" "(" <parameters> ")" <body> ")"
<let> ::= "(let" "(" "[" <variable> <value> "]" ")" <body> ")"
<begin> ::= "(begin" <expressions> ")"
<expressions> ::= <expression> | <expression> <expressions>
<variable> ::= <identifier>
<value> ::= <number> | <string> | <boolean> | <variable> | <function-call>
<function-call> ::= "(" <function-name> <arguments> ")"
<arguments> ::= <value> | <value> <arguments>
<function-name> ::= <identifier>
<identifier> ::= <letter> | <letter> <identifier>
<letter> ::= "a" | "b" | "c" | ... | "z" | "A" | "B" | "C" | ... | "Z"
<number> ::= <digit> | <digit> <number>
<digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<string> ::= "\"" <characters> "\""
<characters> ::= <character> | <character> <characters>
<character> ::= <letter> | <digit> | <symbol>
<symbol> ::= "!" | "@" | "#" | "$" | "%" | "^" | "&" | "*" | "(" | ")" | "-" | "_" | "=" | "+" | "[" | "]" | "{" | "}" | ";" | ":" | "'" | "<" | ">" | "," | "." | "?" | "/"
<boolean> ::= "#t" | "#f"
-
Racket:
(define average (lambda (lst) (/ (foldl (lambda (x y) (+ x y)) 0 lst) (length lst)))) (display (average (list 1 2 3)))
-
Python Output:
from functools import reduce import operator from math import sqrt binary_func_all = lambda func: lambda l: reduce(func, l) add_all = binary_func_all(operator.add) # + sub_all = binary_func_all(operator.sub) # - mul_all = binary_func_all(operator.mul) # * div_all = binary_func_all(operator.truediv) # / all_binary_func = lambda func: lambda l: all([True if func(l[i -1], l[i]) else False for i in range(1, len(l))]) all_eq = all_binary_func(operator.eq) # == all_gt = all_binary_func(operator.gt) # > all_ge = all_binary_func(operator.ge) # >= all_lt = all_binary_func(operator.lt) # < all_le = all_binary_func(operator.le) # <= average = lambda lst: div_all((reduce(lambda x, y: add_all((x, y)), lst, 0), len(lst))) print(average([1, 2, 3]))
-
Parse Tree:
DefineNode ├── IdentifierNode │ └── average └── LambdaNode └── PARAMS └── IdentifierNode └── lst └── EXPRESSION └── DivNode ├── IdentifierNode │ └── lst ├── IdentifierNode │ └── length └── FoldlNode ├── IdentifierNode │ └── lst ├── NumberNode │ └── 0 └── LambdaNode ├── PARAMS │ ├── IdentifierNode │ │ └── x └── IdentifierNode └── y └── EXPRESSION └── AddNode ├── IdentifierNode │ └── y └── IdentifierNode └── x
(display (average (list 1 2 3)))
DisplayNode
└── FunctionCallNodeWithOperands
└── ListNodes
├── NumberNode
│ └── 3
├── NumberNode
│ └── 2
└── NumberNode
└── 1
The translator can be used to convert Racket code for image processing tasks into Python. Here's an example of image thresholding:
-
Racket:
(display (map (lambda (row) (map (lambda (pixel) (if (> pixel 100) 255 0)) row)) (list (list 123 50 200) (list 150 200 255) (list 100 100 100))))
-
Python (translated):
print(map(lambda row: map(lambda pixel: 255 if pixel > 100 else 0, row), [[123, 50, 200], [150, 200, 255], [100, 100, 100]]))
The Abstract Syntax Tree (AST) for the above Racket code is as follows:
DisplayNode
└── MapNode
└── LambdaNode
└── PARAMS
└── IdentifierNode
└── row
└── EXPRESSION
└── MapNode
├── IdentifierNode
│ └── row
└── LambdaNode
└── PARAMS
└── IdentifierNode
└── pixel
└── EXPRESSION
└── IfNode
├── CONDITION
│ ├── GreaterNode
│ │ ├── NumberNode
│ │ │ └── 100
│ │ └── IdentifierNode
│ │ └── pixel
├── THEN
│ ├── NumberNode
│ │ └── 255
└── ELSE
└── NumberNode
└── 0
This demonstrates how the translator converts complex Racket expressions into Python while preserving the functional programming paradigm.
In this section, we present the parse tree graphs generated by AI for the Racket code examples provided in the previous sections. These graphs visualize the abstract syntax trees (ASTs) of the Racket code, showcasing how the code is structured and how different components interact.
These parse tree graphs offer insights into the internal representation of the code and how it is translated into Python. They aid in understanding the transformation process and can be helpful for debugging and code optimization.
The parse tree graphs are generated by AI tools and can be exported as PNG images or PDF files for further analysis and documentation purposes.
This project is licensed under the MIT License.