用Clojure学习The Little Schemer

    The Little Schemer是一部很有名的Lisp书,其中的思想颇具禅意,令我受益匪浅。

    它的作者也很有名,Daniel Friedman。可谓宗师级的人物,王垠就是他的学生之一,有兴趣的朋友可以去了解一下。从王垠记录的一些趣事上来看,他是一位老顽童般授人以渔的教授。从这本书那种启发你思考的风格,也可以看出一二。

;;; learning The Little Schemer

;; Chapter 1.

(def car first)
(def cdr rest)
(def cons clojure.core/cons)
(def eq? =)
(def list? clojure.core/seq?)
(def atom?
  (fn [x]
    (not (list? x))))

(def s-exp? 
  (fn [x]
    (or (atom? x) (list? x))))

(def null?
  (fn [x]
    (and (list? x) (empty? x))))

要小心的去理解上面 atom? 和 null? 的语义,要点是分开 nil 与空表 '() 

我们不期望在这些操作中检测与引入nil语义,我们说一个东西要么是一个原子,要么是一个表(可以是空表)。 

Clojure默认在一些情况下将nil和空表等同起来,有时又不同,比如

> (cons nil nil)
(nil)
> (cons '() nil)
(())
> (cons nil '())
(nil)
> (cons '() '())
(())

;;我的理解是:当参数位置期望是一个表时,nil被当作空表,当期望的是一个原子时,nil作为原子

这样做是符合惯例,事实上遗传自CommonLisp和Java的血统所以不可避免这一点。

你可以这样理解,Scheme世界有逻辑真值,逻辑假值,空表,但没有 nil 这个东西。

由于是第一章内容,所以采用基本的两个形式 def 和 fn 来写。


从第二章开始全部defn,这样递归时看起来会比较美观

;; Chapter 2.

(defn lat? [l]
  (cond (null? l) true
        (atom? (car l)) (lat? (cdr l))
        :else false))

(defn member? [a lat]
  (cond (null? lat) false
        :else (or (eq? (car lat) a)
                  (member? a (cdr lat)))))

可以看到,由于一些语法糖和良好的设计,Clojure代码外观比Scheme或CommonLisp都要更美观一些。

;一开始先这样按照思考的步骤写出来
(defn rember [a lat]
  (cond 
   (null? lat) '()
   :else (cond 
          (eq? (car lat) a) (cdr lat)
          :else (cons (car lat) 
                      (rember a (cdr lat))))))

我的缩进看起来太丑?看到这种 cond 和 else 阶梯状排列的代码,老师会告诉我可以将其排版的更好一些:

;; Chapter 3.

(defn rember [a lat]
  (cond 
   (null? lat) '() 
   (eq? (car lat) a) (cdr lat)
   :else (cons (car lat) 
               (rember a (cdr lat)))))

(defn firsts [l]
  (cond
   (null? l) '()
   :else (cons (car (car l))
               (firsts (cdr l)))))

(defn insertR [new old lat]
  (cond
   (null? lat) '()
   (eq? old (car lat)) (cons old
                             (cons new (cdr lat)))
   :else (cons (car lat)
               (insertR new old (cdr lat)))))

(defn insertL [new old lat]
  (cond
   (null? lat) '()
   (eq? old (car lat)) (cons new 
                             (cons old (cdr lat)))
   :else (cons (car lat)
               (insertL new old (cdr lat)))))

当我能跟着书里规则自然的写代码时,我已经开始明白该如何递归思考了:)


第四章太简单,直接进入下一章~

  ;; Chapter 4.

  (def add1 clojure.core/inc)
  (def sub1 clojure.core/dec)
  (def zero? clojure.core/zero?)

  ;; Chapter 5.
  
  (defn rember* [a l]
    (cond
     (null? l) '()
     (atom? (car l)) (cond
                      (eq? a (car l)) (rember* a (cdr l))
                      :else (cons (car l) (rember* a (cdr l))))
     :else (cons (rember* a (car l)) 
                 (rember* a (cdr l)))))
  
  
  (defn occur* [a l]
    (cond
     (null? l) 0
     (atom? (car l)) (cond 
                      (eq? a (car l)) (add1 (occur* a (cdr l)))
                      :else (occur* a (cdr l)))
     :else (+ (occur* a (car l))
              (occur* a (cdr l)))))





转载于:https://my.oschina.net/wardenlym/blog/300610

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值