8.6
1 Quick Start
racket 有一個奇特的怪僻,就是每個檔案都必須標明自己的
#lang xxx
,一開始只要先記得
#lang racket
就可以了。
1.1 常見的值與表達式
racket 作為一個實用的程式語言,自然有熟悉的概念出現,下面就簡單條列一些常見的值與表達式吧:
;;; 註解是用 ; 為開頭 "我是字串" ; 字串 #t ; True #f ; False 1 ; Integer 3.14 ; Float 4/3 ; Real 3+4i ; Complex e ; 不是,我就只是叫 e 的變數 XD '(1 2 3) ; Listof Integer,也可以寫 (list 1 2 3) ; 兩邊有微妙的差別但暫時還沒有很重要 (λ (x) x) ; lambda,也有人翻譯叫匿名函數,也可以寫成 (lambda (x) x) ; 但在 racket 內建 IDE DrRacket 裡面打出 λ 只需要按 command+\ 非常容易 (define x 1) ; 定義變數 (define (id x) x) ; 定義函數,也可以寫成 (define id (λ (x) x)) ; 但並不會比較好讀 :) (set! x 2) ; 重綁定 x(a.k.a. 賦值) (f a b c) ; 函數呼叫,函數是 f,參數是 a b c
1.2 控制流
作為 Lisp 的主要分支之一,racket 到處都是 () [] 等 S expression,並且稱呼 define 等特殊的表達式為 form。 分辨函數與 form 在 racket 中並不容易,但影響其實不,大因為很少有人會需要弄清楚兩者的差別。 [] 與 () 可以隨意替換使用,這有助於改善可讀性。例如 match 這個用來做 pattern matching 的 form:
(match t [(t:1 _ _ _) #t] [(t:3 a _ c) (a c)] [_ #f])
racket 有數種控制流 form:
(define condition? (= 1 1)) ;;; if form 應該是最簡單的,條件、then-expr、else-expr (if condition? 1 2) ; 1 ;;; cond 後可以接任意個 cond-clause ; 其中每個 cond-clause 都有 test-expr 或是 else pattern ; 當 test-expr 成立,就會執行整串 body,就像 number? x 展示的那樣 (define (is x) (cond [(number? x) (displayln "do something else") "number"] [(string? x) "string"] [else "unknown"])) (is "1") ; "string" (is 2) ; do something else ; "number" ;;; match 就是 pattern matching ; 下面展示了 match 空 list 跟 match 時解開 list 得到 head tail 的情況 (define (reduce x [r 0]) (match x ['() r] [(cons car cdr) (reduce cdr (+ r car))])) (reduce '(1 2 3)) ; 6
更多資訊
1.3 提前中斷
在 racket 中有兩點需要特別注意:
1. 急切求值,簡單來說就是運算會馬上發生,與 Haskell 成為對比。 2. 沒有 return,也沒有 exception。
等等,看到第二點先別急著說這什麼垃圾 www,雖然沒有內建 return 或是 exception,但 racket 提供了更強大的工具 continuation:
(define (foo x) (let/cc return (when (string? x) (return x)) 1)) (foo 1) ;;; 1 (foo "a") ;;; "a" (foo 'a) ;;; 1
雖然在這個案例裡面內建 return 的語言更方便,但 continuation 提供了更多功能,不過這邊就不深入介紹,之後再另開文章寫這個 XD。
1.4 Debug
https://github.com/AlexKnauth/debug 是一個除錯用的函式庫,安裝指令如下
raco pkg install --auto debug
下面是 quick-sort 的案例,展示我們怎麼查看中間狀態
#lang debug racket (define/match (qs l) [((list)) l] [((cons head tail)) (define-values (l b) #R(partition (lamdba (e) (< e head)) l)) (append (qs l) (list head) (qs b))])
#R 是看值
#RR 額外加上行號
#RRR 額外加上行號跟檔案名稱