A Made Up Programming Language__一个小型Interpreter

2024-04-21 20:58

本文主要是介绍A Made Up Programming Language__一个小型Interpreter,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文来源于UW的 PL,part B Assignment 5
原文件已上传到GitHub: 点这里

文章目录

    • Mupl brief introduction
    • Warm-Up
    • Implementing the mupl Language
    • Expanding the Language
    • Using the Language

Mupl brief introduction

mupl (a Made Up Programming Language),是一个用racket编写interpreter,解释执行的mini-functional-language
使用schemecons principle构建了简单的closure系统,支持procedure curry,map,curry等函数式特性。
它的关键字如下:

• If s is a Racket string, then (var s) is a mupl expression (a variable use).
• If n is a Racket integer, then (int n) is a mupl expression (a constant).
• If e1 and e2 are mupl expressions, then (add e1 e2) is a mupl expression (an addition).
• If s1 and s2 are Racket strings and e is a mupl expression, then (fun s1 s2 e) is a mupl expression (a
function). In e, s1 is bound to the function itself (for recursion) and s2 is bound to the (one) argument.
Also, (fun #f s2 e) is allowed for anonymous nonrecursive functions.
• If e1, e2, and e3, and e4 are mupl expressions, then (ifgreater e1 e2 e3 e4) is a mupl expression.
It is a conditional where the result is e3 if e1 is strictly greater than e2 else the result is e4. Only one
of e3 and e4 is evaluated.
• If e1 and e2 are mupl expressions, then (call e1 e2) is a mupl expression (a function call).
• If s is a Racket string and e1 and e2 are mupl expressions, then (mlet s e1 e2) is a mupl expression
(a let expression where the value resulting e1 is bound to s in the evaluation of e2).
• If e1 and e2 are mupl expressions, then (apair e1 e2) is a mupl expression (a pair-creator).
• If e1 is a mupl expression, then (fst e1) is a mupl expression (getting the first part of a pair).
• If e1 is a mupl expression, then (snd e1) is a mupl expression (getting the second part of a pair).
• (aunit) is a mupl expression (holding no data, much like () in ML or null in Racket). Notice
(aunit) is a mupl expression, but aunit is not.
• If e1 is a mupl expression, then (isaunit e1) is a mupl expression (testing for (aunit)).
• (closure env f) is a mupl value where f is mupl function (an expression made from fun) and env
is an environment mapping variables to values. Closures do not appear in source programs; they result
from evaluating functions.

我们可以这样使用它:

(eval-exp (ifgreater (int 3) (int 4) (int 3) (int 2)))				;;get (int 2)
(mlet "x" (int 1) (add (int 5) (var "x")))) 						;;get (int 6)
(snd (apair (int 1) (int 2))))  									;;get (int 2)
(call (closure '() (fun #f "x" (add (var "x") (int 7)))) (int 1))) 	;;get (int 8)
(isaunit (closure '() (fun #f "x" (aunit))))) 						;;get (int 0)
(mlet* (list (cons "x" (int 10))) (var "x"))) 						;;get (int 10)

Warm-Up

MUPL结构定义如下:
相比于definestruct风格更加良好,能够更加精确定义数据。自带get() set(),能够隐藏构造函数来强制invariants.

(struct var  (string) #:transparent)  ;; a variable, e.g., (var "foo")
(struct int  (num)    #:transparent)  ;; a constant number, e.g., (int 17)
(struct add  (e1 e2)  #:transparent)  ;; add two expressions
(struct ifgreater (e1 e2 e3 e4)    #:transparent) ;; if e1 > e2 then e3 else e4
(struct fun  (nameopt formal body) #:transparent) ;; a recursive(?) 1-argument function
(struct call (funexp actual)       #:transparent) ;; function call
(struct mlet (var e body) #:transparent) ;; a local binding (let var = e in body) 
(struct apair (e1 e2)     #:transparent) ;; make a new pair
(struct fst  (e)    #:transparent) ;; get first part of a pair
(struct snd  (e)    #:transparent) ;; get second part of a pair
(struct aunit ()    #:transparent) ;; unit value -- good for ending a list
(struct isaunit (e) #:transparent) ;; evaluate to 1 if e is unit else 0
(struct closure (env fun) #:transparent) 

根据racket list构造mupllist

Similar to Racket, we can build list values out of nested pair values that end with a mupl aunit. Such a
mupl value is called a mupl list

跟scheme一样,mupl的list也是嵌套的pair,以null结尾

(define (racketlist->mupllist rst)(if (null? rst)(aunit)(apair (car rst) (racketlist->mupllist (cdr rst)))))

反过来同理,我们用struct apair定义后的component apair-e1apair-e2来完成构造

(define (mupllist->racketlist pst)(cond [(aunit? pst) null][(apair? pst) (cons (apair-e1 mplst) (mupllist->racketlist (apair-e2 mplst)))]))

Implementing the mupl Language

envlookup,用于查找environment中的variable

(define (envlookup env str)(cond [(null? env) (error "unbound variable during evaluation" str)][(equal? (car (car env)) str) (cdr (car env))][#t (envlookup (cdr env) str)]))

eval-under-env,它接受一个表达式e,并返回e在空环境下计算得到的mul value,或者在求值遇到运行时类型错误或未绑定的变量时调用Racket 's error.
规则如下:

• All values (including closures) evaluate to themselves. For example, (eval-exp (int 17)) would
return (int 17), not 17.
• A variable evaluates to the value associated with it in the environment.
• An addition evaluates its subexpressions and assuming they both produce integers, produces the
integer that is their sum. (Note this case is done for you to get you pointed in the right direction.)
• Functions are lexically scoped: A function evaluates to a closure holding the function and the
current environment.
• An ifgreater evaluates its first two subexpressions to values v1 and v2 respectively. If both
values are integers, it evaluates its third subexpression if v1 is a strictly greater integer than v2
else it evaluates its fourth subexpression.
• An mlet expression evaluates its first expression to a value v. Then it evaluates the second
expression to a value, in an environment extended to map the name in the mlet expression to v.
• A call evaluates its first and second subexpressions to values. If the first is not a closure, it is an
error. Else, it evaluates the closure’s function’s body in the closure’s environment extended to map
the function’s name to the closure (unless the name field is #f) and the function’s argument-name
(i.e., the parameter name) to the result of the second subexpression.
• A pair expression evaluates its two subexpressions and produces a (new) pair holding the results.
• A fst expression evaluates its subexpression. If the result for the subexpression is a pair, then the
result for the fst expression is the e1 field in the pair.
• A snd expression evaluates its subexpression. If the result for the subexpression is a pair, then
the result for the snd expression is the e2 field in the pair.
• An isaunit expression evaluates its subexpression. If the result is an aunit expression, then the
result for the isaunit expression is the mupl value (int 1), else the result is the mupl value
(int 0).

实现:

(define (eval-under-env e env)(cond [(var? e) (envlookup env (var-string e))][(int? e) e][(add? e) (let ([v1 (eval-under-env (add-e1 e) env)][v2 (eval-under-env (add-e2 e) env)])(if (and (int? v1)(int? v2))(int (+ (int-num v1) (int-num v2)))(error "MUPL addition applied to non-number")))][(ifgreater? e)(let ([v1 (eval-under-env (ifgreater-e1 e) env)][v2 (eval-under-env (ifgreater-e2 e) env)])(if (and (int? v1) (int? v2))(if (> (int-num v1) (int-num v2))(eval-under-env (ifgreater-e3 e) env)(eval-under-env (ifgreater-e4 e) env))(error "greater applied to non-number")))][(fun? e) (closure env e)][(closure? e) e][(call? e)(let ([fc (eval-under-env (call-funexp e) env)])(if (closure? fc)(let ([argval (eval-under-env (call-actual e) env)][fucname (fun-nameopt (closure-fun fc))][argname (fun-formal  (closure-fun fc))][fucexpr (fun-body    (closure-fun fc))])(if (string? fucname)(eval-under-env fucexpr (cons (cons fucname fc) (cons (cons argname argval) (closure-env fc))))(eval-under-env fucexpr (cons (cons argname argval) (closure-env fc))))) (error "call first arg applied to non-closure")))][(mlet? e)(if (string? (mlet-var e))(let ([str (mlet-var e)][val (eval-under-env (mlet-e e) env)])(eval-under-env (mlet-body e) (cons(cons str val ) env)))(error "mlet first arg applied to non-string"))][(apair? e)(apair (eval-under-env (apair-e1 e) env)(eval-under-env (apair-e2 e) env))][(fst? e)(let ([v (eval-under-env (fst-e e) env)])(if (apair? v)(apair-e1 v)(error "pair applied to non-pair")))][(snd? e)(let ([v (eval-under-env (fst-e e) env)])(if (apair? v)(apair-e2 v)(error "pair applied to non-pair")))][(isaunit? e)(if (aunit? (eval-under-env (isaunit-e e) env)) (int 1) (int 0))][(aunit? e) (aunit)][#t (error (format "bad MUPL expression: ~v" e))]))(define (eval-exp e)(eval-under-env e null))

对于不太熟悉scheme的人来说,看懂call过程比较需要想象力。它实际上将recursive procedurefuncnameargnameargvalenv进行pack,传给下一层curry
construction process abstractionconstruction data abstraction在这里实现了完美的交融,真正的magic

Expanding the Language

这个部分写一些类似于mupl macrossyntactic sugar扩展语言。

(a) Write a Racket function ifaunit that takes three mupl expressions e1, e2, and e3. It returns a
mupl expression that when run evaluates e1 and if the result is mupl’s aunit then it evaluates e2
and that is the overall result, else it evaluates e3 and that is the overall result. Sample solution:
1 line.
(b) Write a Racket function mlet* that takes a Racket list of Racket pairs ’((s1 . e1) . . . (si . ei)
. . . (sn . en)) and a final mupl expression en+1. In each pair, assume si is a Racket string and
ei is a mupl expression. mlet* returns a mupl expression whose value is en+1 evaluated in an
environment where each si is a variable bound to the result of evaluating the corresponding ei
for 1 ≤ i ≤ n. The bindings are done sequentially, so that each ei is evaluated in an environment
where s1 through si−1 have been previously bound to the values e1 through ei−1.
( c ) Write a Racket function ifeq that takes four mupl expressions e1, e2, e3, and e4 and returns
a mupl expression that acts like ifgreater except e3 is evaluated if and only if e1 and e2 are
equal integers. Assume none of the arguments to ifeq use the mupl variables _x or _y. Use this
assumption so that when an expression returned from ifeq is evaluated, e1 and e2 are evaluated
exactly once each.

(define (ifaunit e1 e2 e3) (ifgreater (isaunit e1) (int 0) e2 e3))(define (mlet* lstlst e2)(if (null? lstlst)e2(mlet (car (car lstlst)) (cdr (car lstlst)) (mlet* (cdr lstlst) e2))))(define (ifeq e1 e2 e3 e4)(mlet "_x" e1 (mlet "_y" e2 (ifgreater (var "_x") (var "_y") e4 (ifgreater (var "_y") (var "_x") e4 e3)))))

从这里我们可以看出来,mlet实际上是用str表示valenv添加约束.

Using the Language

(a) Bind to the Racket variable mupl-map a mupl function that acts like map (as we used extensively
in ML). Your function should be curried: it should take a mupl function and return a mupl
function that takes a mupl list and applies the function to every element of the list returning a
new mupl list. Recall a mupl list is aunit or a pair where the second component is a mupl list.
(b) Bind to the Racket variable mupl-mapAddN a mupl function that takes an mupl integer i and
returns a mupl function that takes a mupl list of mupl integers and returns a new mupl list of
mupl integers that adds i to every element of the list. Use mupl-map (a use of mlet is given to
you to make this easier)

;;外层包装一个匿名函数,封装给内层调用
(define mupl-map(fun #f "f" (fun "calc" "lst" (ifaunit (var "lst")(aunit)(apair (call (var "f") (fst (var "lst"))) (call (var "calc") (snd (var "lst"))))))))(define mupl-mapAddN(fun #f "y"(call mupl-map (fun #f "x" (add (var "x") (var "y"))))))

这篇关于A Made Up Programming Language__一个小型Interpreter的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/924022

相关文章

论文翻译:arxiv-2024 Benchmark Data Contamination of Large Language Models: A Survey

Benchmark Data Contamination of Large Language Models: A Survey https://arxiv.org/abs/2406.04244 大规模语言模型的基准数据污染:一项综述 文章目录 大规模语言模型的基准数据污染:一项综述摘要1 引言 摘要 大规模语言模型(LLMs),如GPT-4、Claude-3和Gemini的快

论文翻译:ICLR-2024 PROVING TEST SET CONTAMINATION IN BLACK BOX LANGUAGE MODELS

PROVING TEST SET CONTAMINATION IN BLACK BOX LANGUAGE MODELS https://openreview.net/forum?id=KS8mIvetg2 验证测试集污染在黑盒语言模型中 文章目录 验证测试集污染在黑盒语言模型中摘要1 引言 摘要 大型语言模型是在大量互联网数据上训练的,这引发了人们的担忧和猜测,即它们可能已

UML- 统一建模语言(Unified Modeling Language)创建项目的序列图及类图

陈科肇 ============= 1.主要模型 在UML系统开发中有三个主要的模型: 功能模型:从用户的角度展示系统的功能,包括用例图。 对象模型:采用对象、属性、操作、关联等概念展示系统的结构和基础,包括类图、对象图、包图。 动态模型:展现系统的内部行为。 包括序列图、活动图、状态图。 因为要创建个人空间项目并不是一个很大的项目,我这里只须关注两种图的创建就可以了,而在开始创建UML图

速通GPT-3:Language Models are Few-Shot Learners全文解读

文章目录 论文实验总览1. 任务设置与测试策略2. 任务类别3. 关键实验结果4. 数据污染与实验局限性5. 总结与贡献 Abstract1. 概括2. 具体分析3. 摘要全文翻译4. 为什么不需要梯度更新或微调⭐ Introduction1. 概括2. 具体分析3. 进一步分析 Approach1. 概括2. 具体分析3. 进一步分析 Results1. 概括2. 具体分析2.1 语言模型

[论文笔记]Making Large Language Models A Better Foundation For Dense Retrieval

引言 今天带来北京智源研究院(BAAI)团队带来的一篇关于如何微调LLM变成密集检索器的论文笔记——Making Large Language Models A Better Foundation For Dense Retrieval。 为了简单,下文中以翻译的口吻记录,比如替换"作者"为"我们"。 密集检索需要学习具有区分性的文本嵌入,以表示查询和文档之间的语义关系。考虑到大语言模

教育LLM—大型教育语言模型: 调查,原文阅读:Large Language Models for Education: A Survey

Large Language Models for Education: A Survey 大型教育语言模型: 调查 paper: https://arxiv.org/abs/2405.13001 文章目录~ 原文阅读Abstract1 Introduction2 Characteristics of LLM in Education2.1.Characteristics of LLM

Nordic Collegiate Programming ContestNCPC 2021

Date:October 9, 2021 Dashboard - 2021-2022 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2021) - Codeforces Problem - C - Codeforces--Customs ControlsProblem - C - Codeforces- 题意:给定一个n个点,m条边

物联网(IoT)支持的小型水处理厂实时硬件在环(HIL)仿真

这篇论文的标题是《Real-Time Hardware-In-The-Loop Simulation of IoT-Enabled Mini Water Treatment Plant》,作者是 Mohamad Taib Miskon 等人,发表在 2024 年 IEEE 自动控制与智能系统国际会议(I2CACIS)上。以下是该论文的主要内容概述: 研究背景: 论文讨论了在马来西亚沙巴州偏远地

If an application has more than one locale, then all the strings declared in one language should als

字符串资源多国语言版本的出错问题 假如你仅仅针对国内语言 加上这句即可 //保留中文支持resConfigs "zh"

Large Language Models(LLMs) Concepts

1、Introduction to Large Language Models(LLM) 1.1、Definition of LLMs Large: Training data and resources.Language: Human-like text.Models: Learn complex patterns using text data. The LLM is conside