Clojure:在 REPL 加载依赖项

编程入门 行业动态 更新时间:2024-10-19 02:26:08
本文介绍了Clojure:在 REPL 加载依赖项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近了解到(感谢技术),在 REPL ---

这失败了:

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

虽然成功了:

user=>(需要 '[clojure.set :as cs])零

在加载 clojure.set 类时.

上下文:前一行是从命名空间的源文件中复制的.

我的主要问题是:通过交换 : 和 ' 字符,我们所做的更改是什么,现在允许后一个命令成功?

我的第二个问题是,总的来说 - 在 REPL 中做事的指导方针是什么 --- 与在普通 clojure 源文件中做事相比? 假设我们可以在这里加载我们的 repl来自 LEININGEN 项目的根目录,因此至少 jars 将在磁盘上的依赖项子目录中可用.

解决方案

我会从高层到您的特定问题:

Clojure(或 LISP)通常如何工作

REPL 或 Read-Eval-Print Loops 是 LISP 设计的核心:

阅读器将字符流转换为数据结构(称为阅读器表单).评估者收集读者表格并对其进行评估.打印机发出求值器的结果.

因此,当您将文本输入到 REPL 中时,它会通过每个步骤来处理您的输入并将输出返回到您的终端.

读者表格

首先是一些clojure阅读器表单.这将非常简短,我鼓励您阅读或观看 (第 1 部分,第 2 部分.>

符号 在 clojure 中是可以表示特定值(如变量)的形式.符号本身可以作为数据传递.它们类似于 c 中的指针,只是没有内存管理的东西.

前面有冒号的符号是关键字.关键字类似于符号,但关键字的值始终是其自身——类似于字符串或数字.它们与 Ruby 的符号相同(也以冒号为前缀).

表单前的引号告诉评估者保持数据结构不变:

user=>(清单 1 2)(1 2)用户=>'(1 2)(1 2)用户=>(= (列表 1 2) '(1 2))真的

虽然引用不仅仅适用于列表,但它主要用于列表,因为 clojure 的评估器通常会将列表作为类似函数的调用来执行.使用 ' 是引用宏的简写:

user=>(引用 (1 2)) ;与 '(1 2) 相同(1 2)

引用基本上指定了要返回的数据结构,而不是要执行的实际代码.所以你可以引用引用符号的符号.

user=>'富;之前没有定义富

引用是递归的.所以里面的所有数据也都引用了:

user=>'(富栏)(富吧)

要获得 (foo bar) 的行为而无需引用,您可以对其进行评估:

user=>(eval '(foo bar)) ;请记住, foo 和 bar 还没有定义.CompilerException java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:1)用户=>(定义 foo 身份)#'用户/foo用户=>(定义栏 1)#'用户/栏用户=>(eval '(foo bar))1

要引用的还有很多,但这超出了范围.

需要

至于 require 语句,我假设您以以下形式找到前者:

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

ns 是一个 宏,它将把 :require 表达式转换成你描述的后一种形式:>

(需要 '[clojure.set :as set])

以及一些命名空间工作.在 REPL 中要求 ns 的文档时描述了基础知识.

user=>(文档 ns)-------------------------clojure.core/ns([name docstring?attr-map?references*])宏将 *ns* 设置为按名称命名的命名空间(未评估),创建它如果需要的话.引用可以是零个或多个:(:refer-clojure ...)(:require ...) (:use ...) (:import ...) (:load ...) (:gen-class)使用引用 clojure/require/use/import/load/gen-class 的语法分别,除了参数是未评估的,不需要引.(:gen-class ...),当提供时,默认为 :name对应于 ns 名称,:main true,:impl-ns 与 ns 相同,以及:init-impl-ns 真.gen-class 的所有选项都是支持的.:gen-class 指令在没有时被忽略编译.如果 :gen-class 未提供,则编译时仅提供一个将生成 nsname__init.class.如果 :refer-clojure 没有被使用,一个使用默认值(请参阅clojure").优先使用 ns对 in-ns/require/use/import 的单独调用:

REPL 用法

一般情况下,REPL 中不要使用 ns,而只使用 requireuse 函数.但是在文件中,使用 ns 宏来做这些事情.

I recently learned (thanks to technomancy) that, at the REPL ---

This fails:

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

Whereas this succeeds :

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

at loading the clojure.set class.

Context: The former line was copied from a namespaced source file.

My primary question is : What is the change we have made, by swapping the : and ' characters, which now allows for success of the latter command ?

My 2nd question is , in general - what are the guidelines for doing things at the REPL --- as compared with doing things in normal clojure source files ? Assume here that we can load our repl from the root of a LEININGEN project, so at least the jars will be available on disk in the dependencies sub directory.

解决方案

I'll go from high-level down to your particular problem:

How Clojure (or LISPs) Generally Work

REPLs, or Read-Eval-Print Loops are the core of how LISPs are designed:

The reader converts a stream of characters into data structures (called Reader Forms). The evaluator takes collection of reader forms and evaluates them. The printer emits the results of the evaluator.

So when you enter text into a REPL, it goes through each of these steps to process your input and return the output to your terminal.

Reader Forms

First some, clojure reader forms. This will be extremely brief, I encourage you to read or watch (part 1, part 2) about it.

A symbol in clojure is form that can represent a particular value (like a variable). Symbols themselves can be pass around as data. They are similar to pointers in c, just without the memory management stuff.

A symbol with a colon in front of it is a keyword. Keywords are like symbols with the exception that a keyword's value are always themselves - similar to strings or numbers. They're identical to Ruby's symbols (which are also prefixed with colons).

A quote in front of a form tells the evaluator to leave the data structure as-is:

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

Although quoting can apply to more than just lists, it's primarily used for lists because clojure's evaluator will normally execute lists as a function-like invocation. Using the ' is shorthand to the quote macro:

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

Quoting basically specifies data structure to return and not actual code to execute. So you can quote symbols which refers to the symbol.

user=> 'foo ; not defined earlier
foo

And quoting is recursive. So all the data inside are quoted too:

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

To get the behavior of (foo bar) without quoting, you can eval it:

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

There's a lot more to quoting, but that's out of this scope.

Requiring

As for require statements, I'm assuming you found the former in the form of:

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

ns is a macro that will transform the :require expression into the latter form you described:

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

Along with some namespacing work. The basics are described when asking for the docs of ns in the REPL.

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 usage

In general, don't use ns in the REPL, and just use the require and use functions. But in files, use the ns macro to do those stuff.

这篇关于Clojure:在 REPL 加载依赖项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

更多推荐

[db:关键词]

本文发布于:2023-03-27 08:52:04,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/686668.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:加载   Clojure   REPL

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!