簡體   English   中英

Clojure:在 REPL 加載依賴項

[英]Clojure : loading dependencies at the 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 類時。

上下文:前一行是從命名空間的源文件中復制的。

我的主要問題是:通過交換 : 和 ' 字符,我們所做的更改什么,現在允許后一個命令成功?

我的第二個問題是,一般來說 - 在 REPL 中做事的指導方針是什么 --- 與在普通 clojure 源文件中做事相比? 假設我們可以從 LEININGEN 項目的根目錄加載我們的 repl,因此至少 jars 將在磁盤上的依賴項子目錄中可用。

我將從高級到您的特定問題:

Clojure(或 LISP)通常如何工作

REPL 或 Read-Eval-Print Loops 是 LISP 設計的核心:

  • 閱讀器將字符流轉換為數據結構(稱為閱讀器表單)。
  • 評估者收集讀者表格並對其進行評估。
  • 打印機發出評估器的結果。

因此,當您在 REPL 中輸入文本時,它會通過每個步驟來處理您的輸入並將輸出返回到您的終端。

讀者表格

首先是一些clojure閱讀器形式。 這將非常簡短,我鼓勵您閱讀或觀看( 第 1 部分第 2 部分)。

clojure 中的符號是可以表示特定值(如變量)的形式。 符號本身可以作為數據傳遞。 它們類似於 c 中的指針,只是沒有內存管理的東西。

前面有冒號的符號是關鍵字 關鍵字類似於符號,但關鍵字的值始終是其自身——類似於字符串或數字。 它們與 Ruby 的符號相同(也以冒號為前綴)。

表單前面的引用告訴評估者保持數據結構不變:

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 ,而只使用requireuse函數。 但是在文件中,使用ns宏來做這些事情。

區別在於require是用於導入代碼的函數,而:require是關鍵字。

記住當您將關鍵字用作函數時會發生什么:

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

它在地圖中查找自己。 因此,當您將[clojure.set :as set]傳遞給關鍵字時,它會嘗試將其計算為向量,但失敗了,因為它不知道clojure.set是什么。 Clojure 文檔說:

關鍵字為一個參數(映射)的 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)))

ns

當你輸入:

(ns some-great-ns 
  :require my-form) 

您使用:require引用,在其中說明您想從給定的命名空間中使用什么。 相當於寫:

(in-ns 'some-great-ns)
(require 'my-form)

請注意,在ns形式中(與in-ns函數調用不同),您不必用'引用您的符號。 您永遠不必在ns引用符號。

require功能

如前所述,可以在某些給定的命名空間中運行:( (require 'some-great-ns) ,以便您可以使用它。 要使用它,您必須使用完全限定名稱,除非您在需要命名空間后立即使用: refer function: (refer 'some-great-ns)

您可以將這兩個功能合二為一: (use 'some-great-ns) 現在你不需要寫: (some-great-ns/my-form )。 簡單地說: my-form

當然,您也可以在宏引用和函數中使用:as:exclude:only:rename關鍵字。

宏和函數的區別:

  1. 如上所述,在函數中使用符號,在宏中不需要
  2. 您可以在(:require)引用中要求多個庫,如下所示:
(ns my-great-namespace.core
  (:require [some-other-ns.a.b :as ab]
            [some-other-other-ns.c.d :as cd]))

function編寫中你應該寫兩行:

(in-ns my-great-namespace.core)
(require 'some-other-ns.a.b :as 'ab)
(require 'some-other-other=ns.c.d :as 'cd)
  1. require引用還允許您引用名稱,例如:
(ns my-great-namespace.core
  (:require [some-other-ns.a.b :refer [some-func]]))

你應該在什么地方做:

(in-ns my-great-namespace.core)
(require 'some-other-ns.a.b)
(refer 'some-other-ns.a.b :only ['some-func])

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM