web-dev-qa-db-ja.com

Clojure:REPLで依存関係をロードする

私は最近(技術のおかげで)REPL ---

これは失敗します:

user=> (:require [clojure.set :as set])
Java.lang.ClassNotFoundException: clojure.set (NO_SOURCE_FILE:24)

これが成功するところ:

user=> (require '[clojure.set :as cs]) 
nil

clojure.setクラスのロード時。

コンテキスト:前の行は名前空間付きのソースファイルからコピーされました。

私の主な質問は次のとおりです::と '文字を入れ替えることにより、後のコマンドを正常に実行できるようになりました。

私の2番目の質問は、一般的に-REPL ---通常のclojureソースファイルでの作業と比較して、作業を行うためのガイドラインは何ですか?ここで仮定しますLEININGENプロジェクトのルートからreplをロードできるため、少なくともjarはディスクの依存関係サブディレクトリで使用できます。

36
jayunit100

私は高レベルからあなたの特定の問題に行きます:

Clojure(またはLISP)の一般的な仕組み

REPLまたはRead-Eval-Printループは、LISPの設計方法の中核です。

  • readerは、文字のストリームを(Reader Formsと呼ばれる)データ構造に変換します。
  • evaluatorはリーダーフォームのコレクションを取り、それらを評価します。
  • printerは、評価者の結果を出力します。

したがって、REPLにテキストを入力すると、これらの各ステップを実行して、入力を処理し、出力を端末に返します。

リーダーフォーム

最初のいくつかは、clojureリーダーのフォームです。これは非常に簡潔です。 read またはそれについて( part 1part 2 )をご覧になることをお勧めします。

Clojureのsymbolは、特定の値(変数など)を表すことができる形式です。シンボル自体をデータとして渡すことができます。これらはcのポインタに似ていますが、メモリ管理機能がありません。

コロンが前にある記号は、keywordです。キーワードはシンボルのようなものですが、キーワードの値は常にそれ自体であり、文字列や数値に似ています。それらはRubyのシンボルと同じです(これにもコロンが付いています)。

フォームの前のquoteは、データ構造をそのままにするように評価者に指示します。

user=> (list 1 2)
(1 2)
user=> '(1 2)
(1 2)
user=> (= (list 1 2) '(1 2))
true

引用はリスト以外にも適用できますが、clojureのエバリュエーターは通常、リストを関数のような呼び出しとして実行するため、リストに主に使用されます。 'の使用は、引用マクロの省略形です。

user=> (quote (1 2)) ; same as '(1 2)
(1 2)

引用は基本的に、返す実際のコードではなく、返すデータ構造を指定します。したがって、シンボルを参照するシンボルを引用できます。

user=> 'foo ; not defined earlier
foo

そして、引用は再帰的です。したがって、内部のすべてのデータも引用されています。

user=> '(foo bar)
(foo bar)

引用せずに(foo bar)の動作を取得するには、それを評価できます。

user=> (eval '(foo bar)) ; Remember, foo and bar weren't defined yet.
CompilerException Java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:1)
user=> (def foo identity)
#'user/foo
user=> (def bar 1)
#'user/bar
user=> (eval '(foo bar))
1

引用することは他にもたくさんありますが、それはこの範囲外です。

必要

Requireステートメントについては、前者が次の形式で見つかったと想定しています。

(ns my.namespace
    (:require [clojure.set :as set]))

nsマクロ で、:require式を、記述した後者の形式に変換します。

(require '[clojure.set :as set])

いくつかのネームスペース作業とともに。 REPLでnsのドキュメントを要求するときに、基本が説明されています。

user=> (doc ns)
-------------------------
clojure.core/ns
([name docstring? attr-map? references*])
Macro
  Sets *ns* to the namespace named by name (unevaluated), creating it
  if needed.  references can be zero or more of: (:refer-clojure ...)
  (:require ...) (:use ...) (:import ...) (:load ...) (:gen-class)
  with the syntax of refer-clojure/require/use/import/load/gen-class
  respectively, except the arguments are unevaluated and need not be
  quoted. (:gen-class ...), when supplied, defaults to :name
  corresponding to the ns name, :main true, :impl-ns same as ns, and
  :init-impl-ns true. All options of gen-class are
  supported. The :gen-class directive is ignored when not
  compiling. If :gen-class is not supplied, when compiled only an
  nsname__init.class will be generated. If :refer-clojure is not used, a
  default (refer 'clojure) is used.  Use of ns is preferred to
  individual calls to in-ns/require/use/import:

REPLの使用法

一般に、REPLでnsを使用せず、require関数とuse関数を使用します。しかし、ファイルでは、nsマクロを使用してこれらのことを行います。

50
Jeff

違いは、requireはコードのインポートに使用される関数であるのに対し、:requireはキーワードです。

キーワードを関数として使用するとどうなるか覚えておいてください。

=> (type :require)
clojure.lang.Keyword
=> (:require {:abc 1 :require 14})
14

自分自身をマップで調べます。したがって、[clojure.set :as set]をキーワードにすると、それはベクトルに評価しようとしますが、何を知っていないために失敗しますclojure.setです。 Clojure docs と言う:

キーワードは、オプションの2番目の引数(デフォルト値)を持つ1つの引数(マップ)のinvoke()のIFnを実装します。たとえば、(:mykey my-hash-map:none)は(get my-hash-map:mykey:none)と同じ意味です。

nsマクロ で混乱している可能性があります:

(ns foo.bar
  (:refer-clojure :exclude [ancestors printf])
  (:require (clojure.contrib sql sql.tests))    ;; here's :require!
  (:use (my.lib this that))
  (:import (Java.util Date Timer Random)
           (Java.sql Connection Statement)))
13
Matt Fenwick