tinylisp:只有99行c代码的lisp语言

源码:Robert-van-Engelen/tinylisp: Lisp in 99 lines of C and how to write one yourself. Includes 21 Lisp primitives, garbage collection and REPL. Includes tail-call optimized versions for speed and reduced memory use.

用99行C代码实现Lisp及自制教程

为了致敬Church和McCarthy的贡献,原作者编写了本项目及配套文章,旨在展示任何人如何用少量C代码或任何类C编程语言编写一个微型Lisp解释器。其尽可能保留了Lisp原有的意义和风格。因此,本项目中的C代码在紧凑形式上具有强烈的Lisp风格。尽管体积小巧,这些C语言编写的微型Lisp解释器包含21个内置Lisp原语、简单的垃圾回收机制和REPL,使其比玩具示例更具实用性。如果需要,可以按照其文章中的说明,通过添加几行C代码轻松增加更多Lisp特性,其中还包含可供尝试的示例。

Tinylisp为何如此小巧?

借助NaN装箱(或BCD装箱)技术以及C语言中的一些编程技巧。有关详细信息、示例以及如何扩展tinylisp功能的详细说明,请参阅文章。

编译tinylisp的方法:

$ cc -o tinylisp tinylisp-opt.c

默认分配的单元格数量为N=1024,仅占用8K内存。要增加内存大小,请修改代码中的N值,然后重新编译tinylisp。

99 行代码 Lisp 语言特性

数字

双精度浮点数,包括inf-infnannanERR相同)。数字也可以用十六进制0xh...h格式输入。

符号

Lisp 符号由一系列非空格字符组成,不包括括号()和引号。在 Lisp 表达式中使用符号时,会查找其值,就像变量通常引用其值一样。符号可以用单引号引用,如'foo,以便按字面意义使用符号或将其传递给函数。

布尔值

嗯,Lisp 其实不需要专门的布尔值。()空列表(称为 nil)被视为 false,任何非()的东西都被视为 true。为方便起见,#t是一个表示 true 的符号(#t计算结果为其自身,即不需要引用)。

列表

在 Lisp 中,列表既是代码也是数据。从语法上讲,可以在列表的最后一个元素使用点号来构造一个序对(pair),而不是列表。例如,'(1 . 2)是一个序对,而'(1 2)是一个列表。由于链表的特性,点号后面的列表会构成一个列表,而不是序对。例如,'(1 . (2 . ()))'(1 2)是相同的。请注意,列表是由序对组成的链,以()结尾。

函数调用

(<函数> <表达式1> <表达式2> ... <表达式n>)

将函数应用于后续的表达式列表作为其参数。以下是所有内置函数,称为“原语”(primitives)和“特殊形式”(special forms)。

引用与解引用

'<表达式> (quote <表达式>)

通过引用保护<表达式>不被求值,效果等同于'<表达式>。例如,'(1 () foo (bar 7))是一个列表,其中包含受引用保护的未求值表达式。

(eval <已引用表达式>)

对已引用的表达式进行求值并返回其结果。例如,(eval '(+ 1 2))的结果是 3。

构造与解构序对和列表

(cons x y)

为表达式xy构造一个序对(x . y)。列表由多个 cons 序对链接而成,其中空列表()作为最后一个y。例如,(cons 1 (cons 2 ()))'(1 2)相同。

(car <序对>)

返回序对(x . y)或列表的第一部分x

(cdr <序对>)

返回序对(x . y)的第二部分y。对于列表,这将返回第一个元素之后的剩余列表。

(pair? x)

如果x是一个序对(即可以应用carcdr的非空列表 cons 单元),则返回#t(真)。

算术运算

(+ n1 n2 ... nk) (- n1 n2 ... nk) (* n1 n2 ... nk) (/ n1 n2 ... nk)

n1nk进行加、减、乘或除运算。计算方式为n1运算符n2运算符 ... 运算符nk。注意,(- 2)的结果是 2,而非 -2,而(- 0 2)的结果是 -2。此外,至少应提供一个数值n。正如文章所建议,你可以根据喜好修改 Lisp 解释器来改变此行为。

(int n)

返回数字n的整数部分。

逻辑运算

(< n1 n2)

如果数字n1<n2,则返回#t(真)。否则,返回()(空列表表示假)。

(eq? x y)

如果值xy完全相同,则返回#t(真)。否则,返回()(空列表表示假)。具有相同值的数字和符号始终是相同的,但非空列表即使值相同也可能不同。

(or x1 x2 ... xk)

返回第一个为真(即非())的x的值。否则,返回()(空列表表示假)。仅求值到第一个为真的x,因此or是条件性的。

(and x1 x2 ... xk)

如果所有x都非(),则返回最后一个x的值。否则,返回()(空列表表示假)。仅求值到第一个为()x,因此and是条件性的。

(not x)

如果x不是(),则返回#t。否则,返回()(空列表表示假)。

条件表达式

(cond (x1 y1) (x2 y2) ... (xk yk))

返回第一个为真的x所对应的y的值,这里的“真”指非()(即非假),且至少有一个条件必须为真。

(if x y z)

如果x为真(即非(),也就是非假),则返回y,否则返回z

lambda 表达式

(lambda )

返回一个匿名函数“闭包”,它包含一个变量列表和一个作为其主体的表达式。例如,(lambda (n) (* n n))会对其参数进行平方运算。lambda 的变量可以是单个名称(不放在列表中),用于将所有参数作为命名列表传递。例如,(lambda args args)会将其参数作为列表返回。可以使用点对(pair dot)来表示剩余的参数。例如,(lambda (f x . args) (f . args))会将函数参数f应用于参数args,同时忽略x。闭包包含 lambda 的词法作用域,即在外层作用域中定义的局部名称可以在主体中使用。例如,(lambda (f x) (lambda args (f x . args)))是一个函数,它接受函数f和参数x以返回一个柯里化函数。

全局变量

(define )

全局定义一个与表达式值相关联的符号。如果该表达式是一个函数或宏,那么这将全局定义该函数或宏。

局部变量

局部变量通过以下let*特殊形式声明。此形式的语法与其他 Lisp 和 Scheme 实现略有不同,目的是让 let 形式更易于直观使用(但如果您愿意,可以在 Lisp 解释器中对其进行修改):

(let* (v1 x1) (v2 x2) ... (vk xk) y)

在符号v的局部作用域内计算y的值,这些符号从第一个到最后一个依次绑定到相应x的值。

注意,大多数 Lisp 使用的语法是将绑定对放在一个列表中,后跟一个或多个主体表达式:

(let* ((v1 x1) (v2 x2) ... (vk xk)) y1 y2 ... yn)

在 tinylisp 中,我们可以通过将除最后一个主体表达式y之外的所有表达式绑定到哑元_变量来实现相同的效果:

(let* (v1 x1) (v2 x2) ... (vk xk) (_ y1) (_ y2) ... yn)

或者,我们可以在let*主体中使用(begin y1 y2 ... yn),其中begin在 common.lisp 中定义。

实践

下载源代码

git clone https://gitcode.com/gh_mirrors/ti/tinylisp cd tinylisp/src

编译

cc -o tinylisp tinylisp-opt.c

编译完成,执行一下:

skywalk@ubjail1:~/github/tinylisp/src$ ls README.md list.lisp tinylisp-extras.c tinylisp-opt.c common.lisp math.lisp tinylisp-float-extras.c tinylisp.c lisp850-opt.c tinylisp tinylisp-float-opt.c lisp850.c tinylisp-commented.c tinylisp-float.c skywalk@ubjail1:~/github/tinylisp/src$ ./tinylisp tinylisp 925>(+ 2 1) 3 925>

注意,退出用Ctrl+D 或者Ctrl+C

只测试了基本(+ 2 1)这样的命令,它给的例子,我能导入,但不知道该怎么调用:

; (sqrt n) -- solve x^2 - n = 0 with Newton method using the Y combinator to recurse ; ... we could add math.h sqrt() as a Lisp primitive, but what's the fun in that? (define Y (lambda (f) (lambda args ((f (Y f)) . args)))) (define sqrt (lambda (n) ((Y (lambda (f) (lambda (x) (let* (y (- x (/ (- x (/ n x)) 2))) (if (eq? x y) x (f y)))))) n)))

好吧,这个是开平方,直接后面带数字就行:

328>(sqrt 9)[ 3 328>

总结

能在99行代码里实现一个可以跑的lisp,还是挺值得学习的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1165473.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 常用编辑器 IntelliJ IDEA,零基础入门到精通,收藏这篇就够了

文章目录 IDEA 概述IDEA 下载和安装IDEA 中的第一个代码IDEA 的项目和模块操作 &#xff08;一&#xff09;类的操作&#xff08;二&#xff09;模块的操作&#xff08;三&#xff09;项目的操作 IDEA 概述 IntelliJ IDEA是一款由JetBrains开发的集成开发环境&#xff08;IDE…

PaddleOCR免费调用API额度提高到3000页每天啦

PaddleOCR&#xff0c;github 60K star&#xff0c;OCR效果非常好&#xff0c;目前是最好的OCR软件。 官网&#xff1a;PaddleOCR - 文档解析与智能文字识别 | 支持API调用与MCP服务 - 飞桨星河社区 除了在官网直接提交文档进行文字识别&#xff0c;还可以使用api调用官方的a…

线程池简单源码思路手撕实现和关于参数设置

线程池简单源码思路手撕实现 import java.util.ArrayList; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit;public class myThreadPool {private int corePoolSize;private int maxPoolSize;private int timeout;pr…

VBScript系统级自动化:使用WScript对象外部操控Office与模拟键盘输入

目录 第七章&#xff1a;WScript控制Office 7-1 WScript常用属性&#xff08;实例&#xff1a;交互性更好的自动拆分工作簿&#xff09; 7-2 WScript对象的常用方法 7-3 用WshShell对象控制程序&#xff08;另一种控制Word、Excel的方法&#xff09; 7-4 用WshShell做机器…

NPP 草原:南非图文巴,1949-1990 年,R1

NPP Grassland: Towoomba, South Africa, 1949-1990, R1 简介 本数据集包含七个文本格式 (.txt) 的数据文件。这些文件提供了在南非图文巴人工建立的草原稀树草原研究地点进行的生物量估算、土壤碳 (C)、氮 (N) 和磷 (P) 测量数据。该研究地点是长期施肥试验的一部分&#xf…

NPP 草原:南非图文巴,1949-1990 年,R1

NPP Grassland: Towoomba, South Africa, 1949-1990, R1 简介 本数据集包含七个文本格式 (.txt) 的数据文件。这些文件提供了在南非图文巴人工建立的草原稀树草原研究地点进行的生物量估算、土壤碳 (C)、氮 (N) 和磷 (P) 测量数据。该研究地点是长期施肥试验的一部分&#xf…

GEE初学:谷歌地球引擎GEE入门指南(最新注册全流程)

引言 谷歌地球引擎(Google Earth Engine, GEE)是一个用于全球尺度地理空间数据分析的强大平台。该平台提供数十年卫星影像和环境数据集的免费访问权限,推动遥感分析的普及化,并支持海量数据的云端处理。 本教程将带您完成从账号创建到首个资源(asset)可视化的完整流程,…

AI应用架构师打造的AI驱动虚拟旅游,树立行业标杆

从0到1构建AI驱动的虚拟旅游应用:AI应用架构师的实战指南 摘要/引言 问题陈述 随着人们对旅游体验多样化需求的增长,传统的实体旅游受到时间、空间以及各种现实因素的限制。如何突破这些限制,为用户提供沉浸式、个性化且不受地理和时间约束的旅游体验,成为旅游行业亟待解…

现代高级语言 JIT 编译优化技术——逃逸分析(Escape Analysis)

现代高级语言 JIT 编译优化技术——逃逸分析&#xff08;Escape Analysis&#xff09;逃逸分析的定义 逃逸分析&#xff08;Escape Analysis&#xff09; 是一种在编译期间&#xff08;对于Java等语言是在即时编译阶段&#xff09;进行的静态分析技术。它的核心目的是分析一个对…

CRM系统如何通过AI与自动化重塑企业销售效能

在数字化转型浪潮中&#xff0c;客户关系管理&#xff08;CRM&#xff09;系统已从简单的客户信息记录工具&#xff0c;演进为企业运营的核心中枢。一款价值型CRM&#xff0c;其关键在于能否将前沿技术深度融入业务场景&#xff0c;实现降本增效。以建广数科自主开发的智盈客CR…

.Net 中的 ActivatorUtilitiesConstructor 特性

.Net 中的 ActivatorUtilitiesConstructor 特性 [ActivatorUtilitiesConstructor] 是 .NET 依赖注入中的一个特性&#xff0c;用于指导 Microsoft.Extensions.DependencyInjection&#xff08;MSDI&#xff09;在类型有多个构造函数时&#xff0c;选择哪个构造函数进行实例化。…

Open Code教程(四)| 高级配置与集成

Open Code教程&#xff08;四&#xff09;| 高级配置与集成OpenCode 高级配置与集成一、前言二、本地模型配置方式一&#xff1a;Ollama&#xff08;推荐&#xff09;方式二&#xff1a;LM Studio方式三&#xff1a;llama.cpp本地模型推荐三、AGENTS.md 配置创建方式推荐结构高…

django-flask基于python的大学生班级档案管理系统

目录django-flask基于python的大学生班级档案管理系统摘要关于博主开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;django-flask基于python的大学生班级档案管理系统摘要 该系统基于Python语…

什么是SR-MPLS

文章目录为什么需要SR-MPLSSR-MPLS vs MPLSSR-MPLS的工作原理从SR-MPLS到SRv6SR-MPLS&#xff08;Segment Routing MPLS&#xff0c;基于MPLS转发平面的段路由&#xff09;是基于源路由理念而设计的在网络上转发数据包的一种协议。SR-MPLS的核心思想是将报文转发路径切割成不同…

救命神器10个一键生成论文工具,专科生毕业论文轻松搞定!

救命神器10个一键生成论文工具&#xff0c;专科生毕业论文轻松搞定&#xff01; AI 工具如何让论文写作变得轻松 对于许多专科生来说&#xff0c;毕业论文的撰写无疑是一道难以逾越的难关。从选题到开题&#xff0c;从查找到写作&#xff0c;每一个环节都可能让人感到力不从心。…

django-flask基于python的大学生创新计划项目管理web系统

目录Django-Flask 基于 Python 的大学生创新计划项目管理 Web 系统摘要关于博主开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;Django-Flask 基于 Python 的大学生创新计划项目管理 Web 系统…

打开软件出现找不到d3dx9_36.dll如何修复? 附免费下载方法

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

学霸同款2026 TOP8 AI论文软件:本科生毕业论文必备测评

学霸同款2026 TOP8 AI论文软件&#xff1a;本科生毕业论文必备测评 2026年学术写作工具测评&#xff1a;为何需要一份精准榜单&#xff1f; 随着AI技术在学术领域的深入应用&#xff0c;越来越多的本科生开始依赖AI工具辅助论文写作。然而&#xff0c;面对市场上琳琅满目的AI论…

django-flask基于python的大学生公益活动志愿服务系统的设计与实现

目录 摘要 关于博主开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01; 摘要 随着社会对公益事业的关注度不断提升&#xff0c;大学生参与志愿服务活动的需求日益增长。传统的志愿服务管理方式…

软件打开提示找不到d3dx9_30.dll文件 如何修复? 附免费下载方法

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…