clojure初心者ガイド(12):ローカルバインド&構文ドメイン
もしあなたがまだ忘れていないなら、前に私たちがどのように変数名にオブジェクトをバインドしたかをよく思い出してください.しかし、当時私たちはグローバルバインドにすぎませんでした.その時、このバインドは非常に役に立ちました.しかし、ローカルバインドは、グローバルバインドよりも適切である場合が多い.例えば、変数を1つの操作内部に制限する場合が多い.次に、バインド関数を使用すると 「let」はローカルバインドを行います.
ローカルバインドでは、変数を操作に制限できます.これにより、他の操作の変数が汚染されません.ローカルバインドがなければ、idという変数名を使用すると、他のオブジェクトをバインドするために使用できなくなります.ローカルバインドを使用すると、ある操作で意味のある変数名を使用することができます.グローバル変数であっても、他の同じ名前の変数と競合することを懸念します.
この動作は通常、文法的役割ドメインと呼ばれ、親操作でも同様の変数名が存在する変数を保護することができます.
例を挙げてみましょう.前回の最後に「data-list」関数を書きました.この関数は最終的に各時間要素を含むリストを返します.呼び出しのたびに、現在の年、月、日、時、分、秒からなるリストを返します.
では、run-reportという関数がほしいです.この関数では、「時」と「分」の2つの要素しか印刷できません.この簡単さは、次のように実現できます.
上の関数に何か問題がありますか?賢いあなたはdata-listという関数が2回呼び出されたことに気づきます.1回は時間を取得し、1回は分を取得します.そうすると2つのデメリットがあります.1つ目は、この2回の呼び出しが返される時間が違います(関数は速くても時間がかかります).非常に誤った結果が得られる可能性があります.最初の呼び出しがちょうど15:59:59で、16点に近い臨界点に達した場合.2番目の呼び出しは16:00:00になりました.この2つの組み合わせは15:00になります.2番目の悪い点は、最初のエラーを排除すると、data-listの実行時間が長い場合、複数回の呼び出しが関数効率に影響を与えることです.
より良い方法は、data-listを1回だけ呼び出し、呼び出した結果をローカル変数にバインドすることです.
次は別の方法です.
文法の役割ドメインについてはこの文章を参考にすることができ、javascriptについてですが、道理は同じです.
=>id
java.lang.Exception: Unable to resolve symbol: id...
=>(let [id 1]
(println id))
1
nil
=>id
java.lang.Exception: Unable to resolve symbol: id...
は、あなたが見ている南陽に向かって、「let」操作を使用することで、「id」という変数名に1をバインドしました.そして、それを印刷しました.この操作が実行された後、「id」を外で表示すると解析できません.これは、変数「id」が操作内部にのみ存在することを証明しています(javaの方法のローカル変数に似ています).ローカルバインドでは、変数を操作に制限できます.これにより、他の操作の変数が汚染されません.ローカルバインドがなければ、idという変数名を使用すると、他のオブジェクトをバインドするために使用できなくなります.ローカルバインドを使用すると、ある操作で意味のある変数名を使用することができます.グローバル変数であっても、他の同じ名前の変数と競合することを懸念します.
=>(def id 0) ;;
#'user/id
=>id
0
=>(let [id 1] ;;
(println id))
1
nil
=>id ;;
0
この動作は通常、文法的役割ドメインと呼ばれ、親操作でも同様の変数名が存在する変数を保護することができます.
=>(let [id 1] ;;
(let [id 2] ;;
(println id)) ;; id
(println id)) ;; id
2
1
nil
例を挙げてみましょう.前回の最後に「data-list」関数を書きました.この関数は最終的に各時間要素を含むリストを返します.呼び出しのたびに、現在の年、月、日、時、分、秒からなるリストを返します.
=>(date-list)
("2013" "07" "10" "15" "02" "59")
=>(date-list)
("2013" "07" "10" "15" "03" "02")
では、run-reportという関数がほしいです.この関数では、「時」と「分」の2つの要素しか印刷できません.この簡単さは、次のように実現できます.
=>(defn run-report []
(str "report ran: " (nth (date-list) 3) ":" (nth (date-list) 4)))
#'user/run-report
=>(run-report)
"report ran: 15:04"
上の関数に何か問題がありますか?賢いあなたはdata-listという関数が2回呼び出されたことに気づきます.1回は時間を取得し、1回は分を取得します.そうすると2つのデメリットがあります.1つ目は、この2回の呼び出しが返される時間が違います(関数は速くても時間がかかります).非常に誤った結果が得られる可能性があります.最初の呼び出しがちょうど15:59:59で、16点に近い臨界点に達した場合.2番目の呼び出しは16:00:00になりました.この2つの組み合わせは15:00になります.2番目の悪い点は、最初のエラーを排除すると、data-listの実行時間が長い場合、複数回の呼び出しが関数効率に影響を与えることです.
より良い方法は、data-listを1回だけ呼び出し、呼び出した結果をローカル変数にバインドすることです.
=>(defn run-report [ ]
(let [date (date-list)] ;;data-list 。date
(str "report ran " (nth date 3) ":" (nth date 4))))
#'user/run-report
=>(run-report)
"report ran: 15:09"
上記の方法では、これまでの2つの問題は存在しませんでした.次は別の方法です.
=>(defn run-report [date]
(str "report ran: " (nth date 3) ":" (nth date 4)))
#'user/run-report
=>(run-report (date-list)) ;;
"report ran: 15:10"
run-raport関数にパラメータdateを追加しました.パラメータは関数にとって暗黙的なローカルバインドです.関数が実行されると、実パラメータでパラメータを置き換えると、ローカルバインドは自動的に暗黙的に行われます.文法の役割ドメインについてはこの文章を参考にすることができ、javascriptについてですが、道理は同じです.