学习交流编程语言理论的平台?

就是元循环求值器,你可以参考:怎样写一个解释器

喔,原来你卡在这里啊。

nameless representation of terms 对初学者确实比较麻烦,主要是实现细节比较多(我记得SICP里也有讲到过它,虽然不是用在同一个地方。。。)

注:nameless representation of terms本质上只是一种优化策略,它并不是这本书的核心(实际上,你使用改名的方法也可以实现同样的目的),建议不要过多的浪费时间在上面。

这个挺有意思,我可以用Emacs Lisp实现一个。

好滴。

没用过 OCaml 是没法理解为什么有些地方要这么设计的。更何况这书是用 OCaml 写 OCaml,不像 Scheme 写 Scheme 顶破天也就那么复杂,要求事先熟悉 OCaml 是很合理的

我觉得能写几道 Project Euler 已经是很低的要求了。再低就是要求写 hello world 了。以 Helium 教学编译器提供的没有 typeclass 的 Haskell98 而论完全掌握真的是很简单了,不比 R6RS 复杂多少。

那刷完我给的那个合集就有同等水平。

我觉得吧,至少写个R5RS的解释器不需要懂这么多东西,会C,看完SICP和TSPL就行。

你说的对 会了C语言 再看懂数据结构与算法 你就能做很多事情了

这个比TAPL简单多了。我的实现跟他的应该差不多。

(require 'pcase)
(require 'cl-lib)

(defun calc (exp)
  (pcase exp
    (`(,op ,e1 ,e2)
     (let ((r1 (calc e1))
           (r2 (calc e2)))
       (pcase op
         ('+ (+ r1 r2))
         ('- (- r1 r2))
         ('* (* r1 r2))
         ('/ (/ r1 r2)))))
    ((pred numberp) exp)))

(defun ext-env (bind env)
  (cons bind env))

(defun ext-envs (bind-list env)
  (append bind-list env))

(defun lookup (var env)
  (cl-loop for bind in env
           for vr = (car bind)
           for va = (cdr bind)
           if (eq var vr)
           return va
           finally return nil))

;; (closure f env)
;; (lambda (x) body)
;; (let (var val) body)
;; (function arg)

(defun interp (exp env)
  (pcase exp
    ;; variable
    ((pred (lambda (e) (and (symbolp e) (not (booleanp e)))))
     (interp (lookup exp env) env))
    ;; single lambda / closure
    (`(lambda . ,_) `(closure ,exp ,env))
    (`(closure . ,_) exp)
    ;; lambda / closure application
    (`((lambda . ,rest) ,arg)
     (interp (list (interp `(lambda . ,rest) env) (interp arg env)) env))
    (`((closure (lambda (,x) ,body) ,e) ,arg)
     (interp body (ext-env (cons x (interp arg (ext-envs e env)))
                           (ext-envs e env))))
    ;; symbol application
    (`(,f ,a) (when (and (symbolp f) (not (booleanp f)))
                (interp `(,(interp f env) ,(interp a env)) env)))
    ;; let
    (`(let (,var ,val) ,body)
     (interp body (ext-env (cons var (interp val env)) env)))
    ;; arithmetic
    ;; op e1 e2 can be confused with let bind body
    (`(+ ,e1 ,e2) (+ (interp e1 env) (interp e2 env)))
    (`(- ,e1 ,e2) (- (interp e1 env) (interp e2 env)))
    (`(* ,e1 ,e2) (* (interp e1 env) (interp e2 env)))
    (`(/ ,e1 ,e2) (/ (interp e1 env) (interp e2 env)))
    ;; number
    ((pred numberp) exp)))
(interp '(let (x (lambda (x) (x 1)))
           (x (lambda (x) (+ 1 x))))
        nil)
;;=> 2

(学Haskell去了

我觉得macro玩得熟练的话,和写解释器是差不多的

其实这本书把所有关于实现的章节都跳过也没什么问题吧。Chapter dependencies 那张图里把4,6,7,10,17,25 都扣掉以后还是 self-contained。(当然这么说有点不负责任,毕竟我只看过几章。)

macro (expender) 和 interpreter 差别还是挺大的吧

对于lisp系,我个人感觉是一样的

Ok,我试试

纠正一个错误,正确的说法是:

任意群G和G上的一个对称群的子群同构 或者说 任意群与某一个置换群同构

这个叫做凯莱定理( Cayley’s theorem ),它可以被看成米田引理(Yoneda lemma)在群论上的推广。

群是它自身的子群,所以没什么错误。

这两天放假,又开始看TAPL。知乎上说最好自己实现一遍lambda calculus的解释器,我就又看了一遍前几章,先用Emacs Lisp实现了一遍。这样之后用Haskell只要照着实现就好了:

感觉挺酷的www。试了几个简单的表达式,感觉没问题,如果有错请告诉我www。

(show (parse '((λ y (λ x x y)) (λ y y))))
;;=> "(λy.λx.xy)(λy.y)"

(show (eval1 (parse '((λ y (λ x x y)) (λ z z)))))
;;=> "λx.x(λz.z)"

P.S. Gist莫名把缩进搞得乱七八糟……

P.P.S. 再打开就又好了……

awesome-course转转,再到网上搜索一下对应最新的课程,然后看看教学文档吧,我没看过,质量应该不会差吧。最近暑假打算看完数据结构,然后看看cs3110

1 个赞

先练练Haskell