/clojure/clojure.rkt

http://github.com/takikawa/racket-clojure · Racket · 287 lines · 229 code · 48 blank · 10 comment · 24 complexity · 98aaaaaafe54ab705b9518b71f24c3f1 MD5 · raw file

  1. #lang racket/base
  2. ;; Clojure compatibility
  3. (require (prefix-in rkt: racket/base)
  4. (prefix-in rkt: racket/set)
  5. racket/stxparam
  6. "nil.rkt"
  7. "printer.rkt"
  8. (for-syntax racket/base
  9. racket/list
  10. syntax/parse
  11. syntax/strip-context
  12. ))
  13. (provide (except-out (all-from-out racket/base)
  14. add1 sub1 if cond #%app #%datum #%top quote)
  15. (rename-out [-#%app #%app]
  16. [-#%datum #%datum]
  17. [-#%top #%top]
  18. [-quote quote]
  19. [sub1 dec]
  20. [add1 inc]
  21. [clojure:cond cond]
  22. [clojure:if if])
  23. def do let fn defn loop recur
  24. -> ->>
  25. partial comp complement constantly
  26. vector str
  27. hash-map map? zipmap get keys vals assoc dissoc
  28. hash-set set? disj
  29. map nth
  30. true false nil boolean not
  31. = == identical?
  32. pr prn pr-str prn-str
  33. )
  34. (define-syntax-parameter recur
  35. ( (stx)
  36. (raise-syntax-error #f "cannot be used outside fn or loop" stx)))
  37. ;; basic forms
  38. (define-syntax (def stx)
  39. (syntax-parse stx
  40. [(_ name:id init)
  41. #'(define name init)]))
  42. (define-syntax-rule (do expr ...)
  43. (begin expr ...))
  44. (define true #t)
  45. (define false #f)
  46. ;; used for let and loop
  47. (begin-for-syntax
  48. (define-splicing-syntax-class binding-pair
  49. #:description "binding pair"
  50. (pattern (~seq name:id val:expr))))
  51. (define-syntax (let stx)
  52. (syntax-parse stx
  53. [(_ #[p:binding-pair ...]
  54. body:expr ...)
  55. #'(let* ([p.name p.val] ...)
  56. body ...)]))
  57. (define-syntax (loop stx)
  58. (syntax-parse stx
  59. [(_ #[p:binding-pair ...]
  60. body:expr ...)
  61. #:with name #'x
  62. #'(letrec ([name (位 (p.name ...)
  63. (syntax-parameterize ([recur (make-rename-transformer #'name)])
  64. body ...))])
  65. (let* ([p.name p.val] ...)
  66. (name p.name ...)))]))
  67. (define-syntax (fn stx)
  68. (syntax-parse stx
  69. [(_ (~optional name:id #:defaults ([name #'x]))
  70. #[param:id ...] body ...)
  71. #'(letrec ([name (位 (param ...)
  72. (syntax-parameterize ([recur (make-rename-transformer #'name)])
  73. body ...))])
  74. name)]
  75. [(_ (~optional name:id #:defaults ([name #'x]))
  76. (#[param:id ...] body ...) ...+)
  77. #'(letrec ([name (syntax-parameterize ([recur (make-rename-transformer #'name)])
  78. (case-lambda
  79. ([param ...] body ...) ...))])
  80. name)]))
  81. (define-syntax (defn stx)
  82. (syntax-parse stx
  83. [(_ name:id expr ...)
  84. #'(define name (fn expr ...))]))
  85. ;; thrush operators
  86. (define-syntax (-> stx)
  87. (syntax-parse stx
  88. [(_ x) #'x]
  89. [(_ x (e e_1 ...))
  90. #'(e x e_1 ...)]
  91. [(_ x e)
  92. #'(-> x (e))]
  93. [(_ x form form_1 ...)
  94. #'(-> (-> x form) form_1 ...)]))
  95. (define-syntax (->> stx)
  96. (syntax-parse stx
  97. [(_ x) #'x]
  98. [(_ x (e e_1 ...))
  99. #'(e e_1 ... x)]
  100. [(_ x e)
  101. #'(->> x (e))]
  102. [(_ x form form_1 ...)
  103. #'(->> (->> x form) form_1 ...)]))
  104. (define (not v)
  105. (or (eq? v #f) (eq? v nil)))
  106. (define (boolean v)
  107. (rkt:not (not v)))
  108. (define-syntax (clojure:if stx)
  109. (syntax-parse stx
  110. [(_ test then)
  111. #'(if (boolean test) then nil)]
  112. [(_ test then else)
  113. #'(if (boolean test) then else)]))
  114. ;; modify lexical syntax via macros
  115. (begin-for-syntax
  116. (define-splicing-syntax-class key-value-pair
  117. (pattern (~seq k:key e:expr)
  118. #:attr pair #'(k.sym e)))
  119. (define-syntax-class key
  120. (pattern e:expr
  121. #:when (clojure-kwd? #'e)
  122. #:attr sym #'(quote e)))
  123. (define (clojure-kwd? e)
  124. (define exp (syntax-e e))
  125. (and (symbol? exp)
  126. (regexp-match #rx":.*" (symbol->string exp)))))
  127. (define-syntax (-quote stx)
  128. (syntax-parse stx
  129. ;; Clojure's quote allows multiple arguments
  130. [(_ e e_1 ...) #'(quote e)]))
  131. (define-syntax -#%datum
  132. (lambda (stx)
  133. (syntax-parse stx
  134. [(-#%datum . #[e ...])
  135. (syntax/loc stx (vector e ...))]
  136. [(-#%datum . hsh)
  137. #:when (syntax-property #'hsh 'clojure-hash-map)
  138. #:with (e ...) (replace-context #'hsh (syntax-property #'hsh 'clojure-hash-map))
  139. (syntax/loc stx (hash-map e ...))]
  140. [(-#%datum . st)
  141. #:when (syntax-property #'st 'clojure-set)
  142. #:with (e:expr ...) (replace-context #'st (syntax-property #'st 'clojure-set))
  143. (syntax/loc stx (hash-set e ...))]
  144. [(-#%datum . e)
  145. (syntax/loc stx (#%datum . e))])))
  146. (define-syntax (-#%app stx)
  147. (syntax-parse stx
  148. [(_ proc:expr arg:expr ...)
  149. #'(#%app proc arg ...)]))
  150. (define-syntax -#%top
  151. (lambda (stx)
  152. (syntax-parse stx
  153. [(-#%top . id)
  154. #:when (syntax-property #'id 'clojure-keyword)
  155. (syntax/loc stx (quote id))]
  156. [(-#%top . id)
  157. (syntax/loc stx (#%top . id))])))
  158. (define-syntax clojure:cond
  159. (lambda (stx)
  160. (syntax-case stx (:else)
  161. [(_)
  162. #'nil]
  163. [(_ :else else-expr)
  164. #'else-expr]
  165. [(_ e1 e2 e3 ...)
  166. (if (even? (length (syntax->list #'(e1 e2 e3 ...))))
  167. #'(if (boolean e1) e2
  168. (clojure:cond e3 ...))
  169. (raise-syntax-error #f "cond requires an even number of forms" stx))])))
  170. ;; lists - examine
  171. (define nth
  172. (case-lambda
  173. [(coll position)
  174. (sequence-ref coll position)]
  175. [(coll position error-msg)
  176. (if (or (= 0 (sequence-length coll))
  177. (> position (sequence-length coll)))
  178. error-msg
  179. (sequence-ref coll position))]))
  180. ;; useful functions
  181. (require racket/function)
  182. (define partial curry)
  183. (define comp compose)
  184. (define complement negate)
  185. (define constantly const)
  186. ;; sequences
  187. (require racket/sequence
  188. racket/stream)
  189. (define (first s) stream-first)
  190. (define (rest s) stream-rest)
  191. (define (cons fst rst) (stream-cons fst rst))
  192. (define map sequence-map)
  193. (define (vector . args)
  194. (apply vector-immutable args))
  195. (define (str . args)
  196. (string->immutable-string
  197. (apply string-append (rkt:map toString args))))
  198. ;; private: can return a mutable string because str will still produce an immutable one
  199. (define (toString v)
  200. (cond [(rkt:string? v) v]
  201. [(nil? v) ""]
  202. [(char? v) (rkt:string v)]
  203. [else (pr-str v)]))
  204. (define (hash-map . args)
  205. (apply hash args))
  206. (define (map? v)
  207. (and (hash? v) (immutable? v)))
  208. (define (hash-set . args)
  209. (apply rkt:set args))
  210. (define (set? v)
  211. (rkt:set? v))
  212. (define (zipmap keys vals)
  213. (for/hash ([k keys] [v vals])
  214. (values k v)))
  215. (define (get map key [not-found nil])
  216. (hash-ref map key ( () not-found)))
  217. (define (keys map)
  218. (hash-keys map))
  219. (define (vals map)
  220. (hash-values map))
  221. (define (assoc map . k/vs)
  222. (apply hash-set* map k/vs))
  223. (define (dissoc map . ks)
  224. (for/fold ([map map]) ([k (in-list ks)])
  225. (hash-remove map k)))
  226. (define (disj set . ks)
  227. (for/fold ([set set]) ([k (in-list ks)])
  228. (rkt:set-remove set k)))
  229. (define (= a . bs)
  230. (for/and ([b (in-list bs)])
  231. (equal? a b)))
  232. (define (== a . bs)
  233. (if (number? a)
  234. (and (andmap number? bs)
  235. (apply rkt:= a bs))
  236. (for/and ([b (in-list bs)])
  237. (equal?/recur a b ==))))
  238. (define (identical? a b)
  239. (eq? a b))