You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Python函数调用转为类Lisp风格表达式实现迷你编程语言

实现类Lisp风格的函数调用解析与求值

核心需求是将带/不带逗号的类Lisp括号表达式,转换为可执行的函数调用,本质是实现一个极简的表达式解析器+求值器,分三步完成:

1. 预处理:统一表达式格式

先消除两种写法的差异,把所有逗号替换为空格,同时清理多余空格,确保括号与元素的分隔清晰:

def preprocess(expr):
    # 去掉所有逗号,替换为空格
    expr = expr.replace(',', ' ')
    # 合并多余空格,保证格式统一
    expr = ' '.join(expr.split())
    return expr

2. 解析表达式为抽象语法树(AST)

将预处理后的字符串拆分为token(括号、函数名、数字),再递归解析成嵌套列表结构——这就是后续可直接求值的AST。比如(say (div (mul 5 (power 9 5)) 3))会被解析为:
['say', ['div', ['mul', 5, ['power', 9, 5]], 3]]

实现代码:

def tokenize(expr):
    # 给括号添加空格,方便拆分出独立token
    expr = expr.replace('(', ' ( ').replace(')', ' ) ')
    return [t for t in expr.split() if t]

def parse(tokens):
    if not tokens:
        raise SyntaxError("Unexpected end of expression")
    token = tokens.pop(0)
    if token == '(':
        ast = []
        while tokens[0] != ')':
            ast.append(parse(tokens))
        tokens.pop(0)  # 移除闭合括号
        return ast
    elif token == ')':
        raise SyntaxError("Unexpected closing parenthesis")
    else:
        # 尝试转换为数字,失败则保留为字符串(函数名)
        try:
            return int(token)
        except ValueError:
            try:
                return float(token)
            except ValueError:
                return token

3. 求值AST,调用对应函数

先定义你的基础函数,再创建函数名与实际函数的映射字典,最后递归遍历AST:遇到列表就取第一个元素作为函数名,递归求值所有参数后调用函数;遇到数字直接返回。

# 定义基础函数
def add(a, b):
    return a + b

def mul(a, b):
    return a * b

def power(a, b):
    return a ** b

def div(a, b):
    if b == 0:
        raise ZeroDivisionError("Division by zero")
    return a / b

def say(value):
    print(value)
    return value

# 函数映射:字符串函数名对应到实际Python函数
function_map = {
    'add': add,
    'mul': mul,
    'power': power,
    'div': div,
    'say': say
}

def eval_ast(ast):
    if isinstance(ast, list):
        func_name = ast[0]
        if func_name not in function_map:
            raise NameError(f"Undefined function: {func_name}")
        func = function_map[func_name]
        # 递归求值所有参数
        args = [eval_ast(arg) for arg in ast[1:]]
        return func(*args)
    else:
        # 数字直接返回
        return ast

完整使用示例

将各模块结合,即可处理两种风格的类Lisp表达式:

# 测试带逗号的表达式
expr1 = "(say, (div, (mul, 5, (power, 9, 5)), 3))"
# 测试不带逗号的表达式
expr2 = "(say (div (mul 5 (power 9 5)) 3))"

for expr in [expr1, expr2]:
    processed = preprocess(expr)
    tokens = tokenize(processed)
    ast = parse(tokens)
    result = eval_ast(ast)
    print(f"输入表达式: {expr}")
    print(f"求值结果: {result}\n")

运行输出:

输入表达式: (say, (div, (mul, 5, (power, 9, 5)), 3))
59049.0
求值结果: 19683.0

输入表达式: (say (div (mul 5 (power 9 5)) 3))
59049.0
求值结果: 19683.0

补充说明

  • 新增函数只需在function_map中添加对应的键值对即可;
  • 当前实现支持任意层级的嵌套表达式,完全覆盖你的需求;
  • 可扩展支持变量、条件表达式等更多语法,当前版本已满足核心功能。

内容的提问来源于stack exchange,提问作者Adras Baros

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 15:30:50