一个支持元循环评估的原生JSON Lambda演算运行时,设计为MCP(模型上下文协议)服务器。它使语言模型能够通过元编程动态演化工具。
快速入门```bash
Build the project
cabal build
Enable debug mode for detailed evaluation tracing
MCP_DEBUG=1 cabal run mcp-pif
Debug output (to stderr) shows:
- Each evaluation step
- Environment keys at each step
- Closure creation and application
- Tool code lookups
### 基本示例```json
// Create a tool
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "evolve",
"arguments": {
"name": "square",
"description": "Squares a number",
"code": {"lam": "x", "body": {"mul": [{"var": "x"}, {"var": "x"}]}}
}
}
}
// Use the tool
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "run",
"arguments": {
"tool": "square",
"input": 7
}
}
}
// Returns: 49
// Get help
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "help",
"arguments": {"category": "lists"}
}
}
// Returns: Documentation for list primitives
核心概念
问题
对于纯粹的计算语言模型来说,需要计算工具,但现有的系统要么提供固定的API,要么允许无限制的代码执行。在元编程和自修改的背景下,这两种方式都不理想。本程序提出了一种折中结构,以实现安全、可检查、可演化的计算。
从理想意义上讲,MCP-PIF可以被视为一种通用的、可变形的计算机接口,其中语言模型作为执行函数被集成进去。在这里,我们提供了一组简单的λ演算原语词汇,仅用于访问纯计算功能。
解决方案
MCP-PIF 提供了一种带有三个元编程原语的 λ 演算:
quote- 将代码视为数据(防止求值)eval- 动态执行带引号的代码code_of- 反思任何工具的源代码
这创造了一个 元循环的 这是一个系统,其中工具能够分析并转换其他工具,同时保持确定性和燃料(资源)受限的执行。它具有同像性,但受到限制。
值得注意的是 quote 和 eval 并不完全对称:``haskell
-- eval cleans the environment:
let cleanEnv = M.filterWithKey (\k _ -> not $ kelem` ["__tool_name", "__self"]) env
这防止了通过 eval 执行的代码继承错误的工具上下文。当 `eval` 执行引用的代码:
- **用户变量会被保留** (保持词法作用域)
- **系统变量已清除** (`__tool_name` 和 `__self` (已移除以避免工具上下文混淆)
- **工具代码仍然可用** (for `code_of` 内省
- **`__eval_depth` 计数器已添加** (最大深度:100,防止无限评估循环)
### 事件视界
由于这个框架是基于MCP构建的,因此在纯粹性上做出了重大妥协。具体来说,更新服务器代码并不是元编程循环的一部分。这意味着,基本元素列表、解析策略以及进化和评估过程本身在运行时是不可修改的。
有两种工具:
- **MCP工具**例如,通过……创建 `evolve` (有副作用,会修改注册表)
- **进化的工具**通过工具执行 `run` (纯粹的,功能性的)
进化后的工具可以相互交互,但在无法访问协议级工具注册表的情况下,它们自身无法进化出新的工具。这种“拟像”实现方式通过隔离那些使丰富元编程成为可能的不变性,防止了无限制的自我修改。
## 语言参考
### 核心基本元素
类别 · 原始类型 · JSON 语法 · 描述
**Lambda** · 变量 · `{"var": "x"}` · 变量引用
功能 · `{"lam": "x", "body": ...}` · Lambda 抽象
应用 · `{"app": {"func": ..., "arg": ...}}` · 函数应用
**算术** · 添加 · `{"add": [a, b]}` · 加法
减去 · `{"sub": [a, b]}` · 减法
乘以 · `{"mul": [a, b]}` · 乘法
分割 · `{"div": [a, b]}` · 除法(对0的错误)
模块 · `{"mod": [a, b]}` · 模块(0时的错误)
**比较** · 等于 · `{"eq": [a, b]}` · 等值测试
少于 · `{"lt": [a, b]}` · 少于
小于或等于 · `{"lte": [a, b]}` 小于或等于
大于 · `{"gt": [a, b]}` 大于
大于或等于 · `{"gte": [a, b]}` 大于或等于
**逻辑** · 和 · `{"and": [a, b]}` 逻辑与(短路)
或者 · `{"or": [a, b]}` · 逻辑或(短路)
否 · `{"not": a}` · 逻辑非
**控制** · 如果 · `{"if": {"cond": c, "then": t, "else": e}}` · 条件
继续 · `{"continue": {"input": x}}` · 递归步骤
**列表** · 无 · `{"nil": true}` · 空列表
缺点 · `{"cons": {"head": ..., "tail": ...}}` · 列表构建
折叠 · `{"fold": [func, init, list]}` · 通用减速器(配对参数详情请参见GUIDE.md文件)
**成对(或配对)** · 配对 · `{"pair": [a, b]}` · 配对构造
第一 · `{"fst": pair}` · 获取第一个元素
第二 · `{"snd": pair}` · 获取第二个元素
**元(Meta)** · 引用 · `{"quote": term}` · 防止评估
评估 · `{"eval": quoted}` · 执行引用代码
代码表 · `{"code_of": "tool_name"}` · 获取工具源码
自己 · `{"self": true}` · 当前闭包引用(仅限工具)
### 字面量
- **布尔值(或布尔类型)**: `true`, `false`
- **字符串**: `"hello"`, `"world"`
- **数组**: `[1, 2, 3]` → 转换为连接列表(或称为表连接)
- **空(或“无”)**: `null` → 单位价值
### 输入归一化
这个(或“该”) `run` 该工具会自动对输入进行规范化处理,以使命令行界面(CLI)的使用更加人性化:
- **字符串数字**: `"42"` → `42`
- **布尔字符串**: `"true"` → `true`, `"false"` → `false`
- **JSON 字符串**: `"{\"x\": 5}"` → 解析为JSON对象
- **列表**JSON 数组被转换为 cons 列表
这允许灵活的输入格式,同时在评估过程中保持类型安全。
## 快速参考
如需查看详细模式和示例,请参阅 **用户指南**。
### 需要记住的关键概念
1. **工具参考**工具可以作为字符串进行引用(`"square"`), 内联lambda表达式,或通过 `code_of`
1. **评估范围界定**用户变量被保留,系统变量被清除,工具代码仍然可用
1. **折叠签名**\`fold\` 函数接收一个单一的配对 `(accumulator, item)`,不是两个参数
1. **继续(或延续)**仅使用注册过的工具,每一步都是一个MCP往返过程
1. **自我指涉**: `{"self": true}` **仅在已注册工具中有效** (通过以下方式创建: `evolve`), **不在内联 lambda 中** 传递给 `run`
1. **事件视界**在λ演算中,工具无法创建其他工具
### 递归快速参考
**需要递归吗?** 使用这个决策树:```
Can you structure it with an accumulator?
├─ Yes → Use `continue` (works for any depth)
│ Pattern: take pair [state, accumulator]
│ Base case: return accumulator
│ Recursive: compute new accumulator, continue with [new_state, new_acc]
│
└─ No, need result immediately?
├─ Small input (n < 20) → Use `self`
└─ Large input → Redesign with accumulator or use fold
示例:
- 阶乘 →
continue使用累加器模式 - 总和 →
continue使用累加器模式 - 斐波那契数列(小n)→
self - 偶数/奇数相互递归 →
eval加号code_of
模式与示例
递归阶乘
工具可以使用基于延续的递归来逐步执行。由于 continue 暂停评估并将控制权返回给MCP层时,你必须使用累加器模式,其中计算在递归过程中进行,而不是在递归之后:```json
{
"name": "evolve",
"arguments": {
"name": "factorial",
"description": "Computes factorial using continuation with accumulator",
"code": {
"lam": "n_acc",
"body": {
"if": {
"cond": {"lte": [{"fst": {"var": "n_acc"}}, 1]},
"then": {"snd": {"var": "n_acc"}},
"else": {
"continue": {
"input": {
"pair": [
{"sub": [{"fst": {"var": "n_acc"}}, 1]},
{"mul": [{"fst": {"var": "n_acc"}}, {"snd": {"var": "n_acc"}}]}
]
}
}
}
}
}
}
}
}
**用法:**```json
{
"name": "run",
"arguments": {
"code": "factorial",
"input": {"pair": [5, 1]}
}
}
该程序将返回一个结构化的响应:```json
{
"type": "continuation",
"message": "Recursive step needed. Call run again with:",
"tool": "factorial_acc",
"next_input": {
"pair": [4, 5]
},
"step": 1
}
这为客户呈现了一个Haskell表示形式:```haskell
Object (fromList [("message",String "Recursive step needed. Call run again with:"),("next_input",Object (fromList [("pair",Array [Number 4.0,Number 5.0])])),("step",Number 1.0),("tool",String "factorial_acc"),("type",String "continuation")])
重要提示: 这个工具接受一对(数据/参数) [n, accumulator] 作为输入。从……开始 [5, 1] 计算5!。每一步递归都将累加器乘以当前的n,然后将n减1。
为什么是这种模式?
该 continue 原生函数并不返回一个你可以用以进行计算的值,而是返回一个延续标记。所有的计算都必须在调用之前完成 continue存储在累加器中。模式是:
- 输入:
[n, acc]哪里acc保存部分结果 - 基本情况: 当
n ≤ 1,返回累加器 - 递归情况: 计算新的累加器(
n * acc),继续进行[n-1, new_acc]
备选方案:使用直接递归 self (燃料限制):```json
{
"name": "evolve",
"arguments": {
"name": "factorial_self",
"description": "Simple factorial using self (small n only)",
"code": {
"lam": "n",
"body": {
"if": {
"cond": {"lte": [{"var": "n"}, 1]},
"then": 1,
"else": {
"mul": [
{"var": "n"},
{"app": {"func": {"self": true}, "arg": {"sub": [{"var": "n"}, 1]}}}
]
}
}
}
}
}
}
这种方法对于小规模输入有效,但在n≈20时会达到燃料限制(10,000步)。
### 通过折叠实现高阶映射```json
{
"name": "map",
"description": "Maps a function over a list",
"code": {
"lam": "f",
"body": {
"lam": "list",
"body": {
"fold": [
{"lam": "acc_item", "body": {
"cons": {
"head": {"app": {"func": {"var": "f"}, "arg": {"snd": {"var": "acc_item"}}}},
"tail": {"fst": {"var": "acc_item"}}
}
}},
{"nil": true},
{"var": "list"}
]
}
}
}
}
元编程:代码分析```json
{
"name": "count_operations",
"description": "Counts arithmetic operations in a tool",
"code": {
"lam": "tool_name",
"body": {
"eval": {
"quote": {
"analyze": [{"code_of": {"var": "tool_name"}}]
}
}
}
}
}
该 `code_of` \`primitive\` 返回工具的源代码作为引用数据,从而支持程序分析和转换。
## 建筑学
### 管道```
JSON Input → Parser → Term → Evaluator → RuntimeValue → Encoder → JSON Output
validation syntax execution values serialization
模块
| 模块 | 用途 |
|---|---|
| Main.hs | 入口点,JSON-RPC 循环 |
安全保证
- 基于燃料的终止每次评估都有有限的步骤(默认:10,000步)
- 纯粹的评价在λ演算中没有输入/输出或效果
- 验证后的执行只有结构上有效的术语才能运行
- 不可变注册表工具在执行过程中不能相互修改
MCP集成
MCP-PIF 实现了用于工具发现和执行的模型上下文协议:
系统工具
evolve- 创建新工具(在注册表中存储)run- 执行工具或内联lambda表达式list- 显示所有已注册的工具help- 显示基本元素和系统工具的文档
协议流程
- 客户端向标准输入发送JSON-RPC请求
- 服务器解析并路由到相应的处理程序
- 对于工具执行:
- 解析输入JSON → 术语
- 将工具代码注入到环境中
- 在燃料限制下进行评估
- 编码结果 → JSON - 响应已发送到标准输出
连接MCP客户端```python
Example using Python MCP SDK
import mcp
async with mcp.Client() as client:
await client.connect(stdio_transport("cabal run mcp-pif"))
Create a tool
await client.call_tool("evolve", {
"name": "double",
"description": "Doubles a number",
"code": {"mul": [{"var": "x"}, 2]}
})
Use it
result = await client.call_tool("run", {
"tool": "double",
"input": 21
})
print(result) # 42
```
未来方向
MCP-PIF的当前设计在纯计算与具有副作用的操作之间保持了清晰的界限。我们已经考虑了几种扩展方式,这些方式将以有趣的方式拓展这些界限:
分析函数
当前系统主要是 合成的 - 使用基本元素来组合新函数。一个自然的扩展就是 分析性的 能力:
- 验证未进行评估的期限结构静态分析
- 规范化将项简化为规范形式
- 等价性检查证明两个项计算的是同一个函数
- 类型推断为lambda项推导类型
- 复杂性分析估算燃料需求
- 能力分析按基本元素分解工具
这些分析函数将对作为数据的代码(引号中的术语)进行操作,并可能实现强大的元编程模式。然而,它们需要经过精心设计,以在保持核心演算简洁性的同时,提供有意义的保证。
高效的原语(或基本操作)
另一个方向涉及有控制地引入影响:
系统交互:
- 文件输入/输出原语(
readFile,writeFile) - 过程控制(
exec,env) - 网络运营(
fetch,serve)
设计挑战:
- 如何维护纯洁的界限?
- 效果应该是单子式的、代数式的,还是基于延续的?
- 如何处理错误和资源管理?
- 能力控制采用哪种安全模型?
一种方法可能是 基于能力的安全工具可以在创建时声明所需的能力(如文件访问、网络等),而MCP层则负责强制执行访问控制。这与进化工具应承担证明其自身有效性的理念是一致的。
自托管与自举启动
终极的元循环目标:在MCP-PIF自身中实现MCP-PIF的评估器。这将需要:
- 用于JSON操作的基本函数/方法
- 模式匹配构造
- 环境的有效表示
- 元级别的燃料管理
一个自托管的PIF(编程接口框架)能够实现评估策略本身的运行时进化——一个真正具有自省能力的系统。
协议扩展
MCP边界可以支持额外的协议级操作:
- 工具版本管理跟踪工具随时间的演变
- 工具构成工具融合的协议级组合器
- 分布式注册表在MCP服务器之间共享工具
- 证明证书为工具附加正确性证明
这些扩展在保持事件视界原则的同时,增强了协议层的功能。
任何扩展的关键设计原则是:保持PIF作为语言模型计算可靠基底的简洁性和可预测性。
许可证
麻省理工学院(MIT)
