Masalahnya di sini tidak kentara dan mungkin sulit untuk diatasi tanpa terlebih dahulu memahami sedikit tentang makro.
Makro memanipulasi sintaksis dengan cara yang sama seperti fungsi memanipulasi nilai. Faktanya, makro hanyalah fungsi dengan kait yang menyebabkannya dievaluasi pada waktu kompilasi. Mereka meneruskan data literal yang Anda lihat di kode sumber dan dievaluasi dari atas ke bawah. Mari kita buat fungsi dan makro yang memiliki isi yang sama sehingga Anda dapat melihat perbedaannya:
(defmacro print-args-m [& args]
(print "Your args:")
(prn args))
(defn print-args-f [& args]
(print "Your args:")
(prn args))
(print-args-m (+ 1 2) (str "hello" " sir!"))
; Your args: ((+ 1 2) (str "hello" " sir!"))
(print-args-f (+ 1 2) (str "hello" " sir!"))
; Your args: (3 "hello sir!")
Makro diganti dengan nilai kembaliannya. Anda dapat memeriksa proses ini dengan macroexpand
(defmacro defmap [sym & args]
`(def ~sym (hash-map ~@args))) ; I won't explain these crazy symbols here.
; There are plenty of good tutorials around
(macroexpand
'(defmap people
"Steve" {:age 53, :gender :male}
"Agnes" {:age 7, :gender :female}))
; (def people
; (clojure.core/hash-map
; "Steve" {:age 53, :gender :male}
; "Agnes" {:age 7, :gender :female}))
Pada titik ini, saya mungkin harus menjelaskan bahwa '
menyebabkan formulir berikut menjadi quote
d. Artinya compiler akan membaca form, tapi tidak mengeksekusinya atau mencoba menyelesaikan simbol dan sebagainya. yaitu 'conj
mengevaluasi ke suatu simbol, sedangkan conj
mengevaluasi ke suatu fungsi. (eval 'conj)
setara dengan (eval (quote conj))
setara dengan conj
.
Dengan mengingat hal tersebut, ketahuilah bahwa Anda tidak dapat menyelesaikan simbol sebagai namespace sampai simbol tersebut telah diimpor secara ajaib ke dalam namespace Anda. Inilah yang dilakukan fungsi require
. Dibutuhkan simbol dan menemukan namespace yang sesuai, membuatnya tersedia di namespace saat ini.
Mari kita lihat apa yang diperluas oleh makro ns
:
(macroexpand
'(ns sample.core
(:require clojure.set clojure.string)))
; (do
; (clojure.core/in-ns 'sample.core)
; (clojure.core/with-loading-context
; (clojure.core/refer 'clojure.core)
; (clojure.core/require 'clojure.set 'clojure.string)))
Lihat bagaimana ia mengutip simbol clojure.set
dan clojure.string
untuk kita? Alangkah nyaman! Tapi apa masalahnya jika Anda menggunakan require
sebagai pengganti :require
?
(macroexpand
'(ns sample.core
(require clojure.set clojure.string)))
; (do
; (clojure.core/in-ns 'sample.core)
; (clojure.core/with-loading-context
; (clojure.core/refer 'clojure.core)
; (clojure.core/require 'clojure.set 'clojure.string)))
Tampaknya siapa pun yang menulis makro ns
cukup baik membiarkan kami melakukan keduanya, karena hasil ini persis sama seperti sebelumnya. rapi!
edit: tvachon benar hanya menggunakan :require
karena ini adalah satu-satunya formulir yang didukung secara resmi
Tapi apa masalahnya dengan tanda kurung?
(macroexpand
'(ns sample.core
(:require [clojure.set]
[clojure.string])))
; (do
; (clojure.core/in-ns 'sample.core)
; (clojure.core/with-loading-context
; (clojure.core/refer 'clojure.core)
; (clojure.core/require '[clojure.set] '[clojure.string])))
Ternyata mereka juga dikutip, sama seperti yang kita lakukan jika kita menulis panggilan mandiri ke require
.
Ternyata ns
juga tidak peduli apakah kita memberikannya daftar (paren) atau vektor (tanda kurung) untuk dikerjakan. Ia hanya melihat argumen sebagai rangkaian hal. Misalnya, ini berfungsi:
(ns sample.core
[:gen-class]
[:require [clojure.set]
[clojure.string]])
require
, seperti yang ditunjukkan oleh amalloy di komentar, memiliki semantik yang berbeda untuk vektor dan daftar, jadi jangan bingung!
Terakhir, mengapa cara berikut ini tidak berhasil?
(ns sample.core
(:require 'clojure.string 'clojure.test))
Nah, karena ns
yang mengutip untuk kita, simbol-simbol ini dikutip dua kali, yang secara semantik berbeda dengan dikutip hanya sekali dan juga murni kegilaan.
conj ; => #<core$conj clojure.core$conj@d62a05c>
'conj ; => conj
''conj ; => (quote conj)
'''conj ; => (quote (quote conj))
Saya harap ini membantu, dan saya merekomendasikan mempelajari cara menulis makro. Itu sangat menyenangkan.
person
d.j.sheldrick
schedule
09.04.2013