英和訓練

著作権は原文に属します

Learn Clojure - Syntax 構文

Literals リテラル

Below are some examples of literal representations of common primitives in Clojure. Clojureで一般的な基本要素らのリテラル表現のいくつかの例を次に示す。

The ; creates a comment to the end of the line. ; 以降行末まではコメントとなる。Sometimes multiple semicolons are used to indicate header lines. 見出し行であることを表すためにしばしば複数のセミコロンが使われる。

;; Numeric types 数値型
42              ; Long - 64-bit integer (from -2^63 to 2^63-1) ロング型 - 64ビット整数(-2の63乗から2の63乗-1まで)
6.022e23        ; Double - double-precision 64-bit floating point ダブル型 - 64ビット倍精度浮動小数点数
42N             ; BigInt - arbitrary precision integer ビッグイント型 - 任意制度整数
1.0M            ; BigDecimal - arbitrary precision fixed-point decimal ビッグデシマル型 - 任意制度固定小数点十進数
22/7            ; Ratio 比

;; Character types 文字型
"hello"         ; String 文字列
\e              ; Character 文字

;; Other types その他の型
nil             ; null value null値
true            ; Boolean (also, false) (trueのみならずfalseも含めて)真義値
#"[0-9]+"       ; Regular expression 正規表現
:alpha          ; Keyword キーワード
:release/alpha  ; Keyword with namespace 名前空間つきキーワード
map             ; Symbol シンボル
+               ; Symbol - most punctuation allowed シンボル - たいていの記号文字が使える
clojure.core/+  ; Namespaced symbol 名前空間つきシンボル

All of the literals above are valid Clojure expressions. 上に示した全てのリテラルはそれぞれ、Clojureにおける有効な式である。

Clojure also includes literal syntax for four collection types: Clojureではまた、以下に示す4種類のコレクション型のリテラルがある。

'(1 2 3)     ; list リスト
[1 2 3]      ; vector ベクタ
#{1 2 3}     ; set セット
{:a 1, :b 2} ; map マップ

We'll talk about these in much greater detail later - for now it's enough to know that these four data structures can be used to create composite data. これらについては後で詳しく説明する。今のところは、複合的データを作るためにこれら4種類のデータ構造が利用できることを記憶にとどめてくれればよい。

Evaluation 評価

Next we will consider how Clojure reads and evaluates expressions. Clojureがどのように式を読み、評価しているかについて考えてみよう。

Traditional Evaluation (Java) 従来一般的な評価(ジャバ)

図版省略
compilation unit = file or class コンパイル単位 = ファイルないしクラス
Source Code ソースコード
characters 文字ら
Compiler コンパイラ
bytecode バイトコード
JVM Java仮想マシン
Effect 効果

In Java, source code (.java files) are read as characters by the compiler (javac), which produces bytecode (.class files) which can be loaded by the JVM. Javaでは、ソースコード(.javaファイルら)が文字の集まりとしてコンパイラ(javac)に読まれ、コンパイラが出力したバイトコード(.classファイルら)がJVMによってロードされる。

Clojure Evaluation Clojureにおける評価

図版省略
compilation unit = expression コンパイル単位 = 式
Source Code ソースコード
characters 文字ら
You あなた
Reader リーダ
data structure データ構造
Compiler コンパイラ
bytecode バイトコード
JVM Java 仮想マシン
Effect 効果

In Clojure, source code is read a characters by the Reader. Clojureではソースコードの文字らはリーダに読み込まれる。The Reader may read the source either from .clj files or be given a series of expressions interactively. リーダには、.cljファイルから読み込ませることもできるし、連続する式をインタラクティブに与えて読み込ませることもできる。リーダはClojureのデータを生む。次に、ClojureコンパイラJVMのためのバイトコードを生成する。

There are two important points here: ここでの要点は次の2つだ。

  1. The unit of source is a Clojure expression, not a Clojure source file. ソースコードの単位はClojureの式であり、ソースファイルではない。Source files are read as a series of expressions, just as if you typed those expressions interactively at the REPL. ソースファイルらは連続する複数の式として読み込まれる。そのことは、あなたがREPLでインタラクティブにそれらの式をキーボードで入力した場合と変わらない。
  2. Separating the Reader and the Compiler is a key separation that makes room for macros. リーダとコンパイラを分けることは、大切な分割であって、それによってマクロのための余地が生まれる。Macros are special functions that take code (as data), and emit code (as data). マクロは、コードを(データとして)受け取り、コードを(データとして)吐き出す、特別な機能である。Can you see where a loop for macro expansion could be inserted in the evaluation model? 上図の評価モデルにおいて、マクロ展開のためのループがどこに挿入されるか、わかるだろうか?

Structure vs Semantics 構造と意味論の違い

このClojureの式を考えてみよう。

図版省略
List リスト
Symbol シンボル
Numbers 数
Invocation 呼び出し
Function 関数
Arguments 引数

This diagram illustrates the difference between syntax in green (the Clojure data structure produced by the Reader) and semantics in blue (how that data is understood by the Clojure runtime). この図は、緑色で書かれた構文と、青色で書かれた意味論との違いを表している。構文は、リーダから生成される、Clojureのデータ構造であり、一方で意味論は、Clojureの実行環境によってそのデータがどのような意味に解釈されるかということだ。

Most literal Clojure forms evaluate to themselves, except symbols and lists. Clojureのほとんどのリテラルのフォームはそれ自身へと評価される。ただし、シンボルとリストはそうではない。Symbols are used to refer to something else and when evaluated, return what they refer to. シンボルはそれ自身ではない何かを指し示すために用いられ、評価されると、指し示すそれを返す。Lists (as in the diagram) are evaluated as invocation. リストは(図に示したように)呼び出しとして評価される。

In the diagram, (+ 3 4) is read as a list containing the symbol (+) and two numbers (3 and 4). 図の場合、(+ 3 4)は、1つのシンボル(+)と2つの数(3と4)を含むリストとして読み込まれる。 The first element (where + is found) can be called "function position", that is, a place to find the thing to invoke. (ここでは+が見つかる)1つ目の要素は「関数の位置」と呼ばれて、呼び出すべきものが探される場所である。While functions are an obvious thing to invoke, there are also a few special operators known to the runtime, macros, and a handful of other invokable things. 呼び出すものとしては関数が代表的だが、他に、実行環境が知っている特殊な演算子が少しと、マクロと、もういくつかの呼び出せるものがある。

Considering the evaluation of the expression above: 上の式の評価を考えてみよう。

  • 3 and 4 evaluate to themselves (longs). 3と4はそれ自身(ロング型の値)へと評価される。
  • + evaluates to a function that implements + +は加算を実装する関数へと評価される。
  • evaluating the list will invoke the + function with 3 and 4 as arguments リスト全体を評価することは、3と4を引数として+関数を呼び出すことになる。

Many languages have both statements and expressions, where statements have some stateful effect but do not return a value. 多くの言語には文と式の両方があり、文とは、状態に対する効果を持つが値を返すことはないものだとされる。In Clojure, everything is an expression that evaluates to a value. Clojureでは全ては式であり、それぞれの式は値へと評価される。Some expressions (but not most) also have side effects. (多数派ではないが)一部の式は、副作用も持っている。

Now let's consider how we can interactively evaluate expressions in Clojure. では次に、Clojureで、インタラクティブに式を評価する方法について見てみよう。

Delaying evaluation with quoting クォートによって評価を遅らせる

Sometimes it's useful to suspend evaluation, in particular for symbols and lists. シンボルやリストについて特にそうだが、評価を遅らせることが便利な時がある。Sometimes a symbol should just be a symbol without looking up what it refers to: シンボルを、それが指し示すものを問うのためではなく、シンボル自身として扱いたい時がある。

user=> 'x
x

And sometimes a list should just be a list of data values (not code to evaluate): リストもまた、評価すべきコードとしてではなく、データの値のリストそのものであってほしい時がある。

user=> '(1 2 3)
(1 2 3)

One confusing error you might see is the result of accidentally trying to evaluate a list of data as if it were code: データのリストを誤ってコードのように評価させてしまった時には、次のようなエラーが出て驚くかもしれない。

user=> (1 2 3)
ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn

For now, don't worry too much about quote but you will see it occasionally in these materials to avoid evaluation of symbols and lists. クォートのこの機能についてここで気にしすぎる必要はない。しかし、今後の説明において、シンボルやリストの評価を避けるためのクォートを、しばしば目にすることになるだろう。

REPL

Most of the time when you are using Clojure, you will do so in an editor or a REPL (Read-Eval-Print-Loop). Clojureを使う時にはほとんどの場合、エディタかREPLで使うことだろう。(REPLというのは、読み込み・評価・出力・繰り返し、の省略表現だ。)The REPL has the following parts: REPLは次の要素からなる。

  1. Read an expression (a string of characters) to produce Clojure data. Clojureのデータを生じるために一つの式(ある文字列)を読み取る。
  2. Evaluate the data returned from #1 to yield a result (also Clojure data). 1.で得たデータを評価して、(これもまたClojureのデータである)データを生む。
  3. Print the result by converting it from data back to characters. そのデータを文字列へと変換して出力する。
  4. Loop back to the beginning. 1.の処理に反復的に戻る。

One important aspect of #2 is that Clojure always compiles the expression before executing it; 2.について閑却できない側面の一つは、Clojureは、式を評価するまえにいつもその式をコンパイルするということである。Clojure is always compiled to JVM bytecode. Clojureのコードは常にJVMバイトコードへとコンパイルされる。There is no Clojure interpreter. Clojureインタプリタはない。

user=> (+ 3 4)
7

The box above demonstrates evaluationg an expression (+ 3 4) and receiving the result. 上の枠内は、式 (+ 3 4) を評価し、その評価結果を受け取った様を例示している。

Exploring at the REPL REPLによる探検

Most REPL environments support a few trick to help with interactive use. 多くのREPL環境には、インタラクティブな利用を助けるためのいくつかの仕掛けがある。For example, some special symbols rememver the results of evaluating the last three expressions: 例えば、次のシンボルにはそれぞれ、最後に行われた3つの評価の結果が記録されている。

  • *1 (the last result) (最後の結果)
  • *2 (the result two expressions ago) (2つ前の評価結果)
  • *3 (the result three expressions ago) (3つ前の評価結果)
user=> (+ 3 4)
7
user=> (+ 10 *1)
17
user=> (+ *1 *2)
24

In addition, there is a namespace clojure.repl that is included in the standard Clojure library that provides a number of helpful functions. さらに、標準のClojureライブラリにはclojure.replという名前空間が含まれていて、便利な関数をいくつか提供している。To load that library and make its functions available in our current context, call: そのライブラリをロードして、それら関数を現在のコンテキストで利用可能にするには、次の呼び出しを行う。

(require '[clojure.repl :refer :all])

For now, you can treat that as a magic incantation. 今のところ、これはおまじないの呪文だと思っていい。Poof! ナムナムってね。We'll unpack it when we get to namespaces.名前空間について説明する時に、この詳細は説明しよう。

We now have access to some additional functions that are useful at the REPL: これによって、REPLで便利ないくつかの関数が追加で使えるようになった。 doc, find-doc, apropos, source, and dir.

The doc function displays the documentation for any function. doc関数は任意の関数についてドキュメンテーションを表示する。Let's call it on +: +についてdocを呼んでみよう。

user=> (doc +)

clojure.core/+
([] [x] [x y] [x y & more])
  Returns the sum of nums. 数らの和を返す。
  (+) returns 0. (+)は0を返す。 
  Does not auto-promote longs, will throw on overflow. ロング値から型を自動拡張することはなく、オーバフローの際には例外を投げる。
  See also: +'

The doc function prints the documentations for +, including the valid signatures. doc関数で+のドキュメンテーションを印字した。+のシグネチャも表示されるので、引数の与え方もわかる。

The doc function prints the documentation, then returns nil as the result - you will see both in the evaluation output. doc関数は解説を表示しnilを返す。よって、REPLで使えばその両方を見ることになるだろう。

We can invoke doc on itself too: doc自身に対してdocできる。

user=> (doc doc)

clojure.repl/doc
([name])
Macro
  Prints documentation for a var or special form given its name
  与えられた名前を持つvarないし特殊形式のドキュメンテーションを表示する

Not sure what something is called? そもそも呼び出すものの名前が分からなかったら? You can use the apropos command to find functions that match a particular string or regular expression. apropos(適宜)コマンドによって、文字列の一部や正規表現で関数を探すことができる。

user=> (apropos "+")
(clojure.core/+ clojure.core/+')

You can also widen your search to include the docstrings themselves with find-doc: find-docを使えば、docstringも含めて一覧できる。

user=> (find-doc "trim")

clojure.core/subvec
([v start] [v start end])
  Returns a persistent vector of the items in vector from start (inclusive) to end (exclusive).
  ベクタのstart(含む)からend(含まない)までの要素を永続的ベクタとして返す。
  If end is not supplied, defaults to (count vector).
  省略された時のendの値は(count vector)である。
  This operation is O(1) and very fast, as the resulting vector shares structure with the original and no trimming is done.
  この処理はO(1)であって速い。結果のベクタはオリジナルと構造を共有し、トリミングは行われないからである。

clojure.string/trim
([s])
  Removes whitespace from both ends of string.
  文字列の両側から空白文字を除く。

clojure.string/trim-newline
([s])
  Removes all trailing newline \n or return \r characters from string.
  文字列から改行文字 \n または \r を全て除く。
  Similar to Perl's chomp. Perlにおけるchompのようなものである。

clojure.string/triml
([s])
  Removes whitespace from the left side of string.
  文字列の左側の空白文字を除く。

clojure.string/trimr
([s])
  Removes whitespace from the right side of string.
  文字列の右側の空白文字を除く。

If you'd like to see a full listing of the functions in a particular namespace, you can use the dir function. ある名前空間に存在する全ての関数の一覧を見てみたくなったら、dir関数が使える。Here we can use it on the clojure.repl namespace: 例えばclojure.replという名前空間の関数の一覧を次のように見られる。

user=> (dir clojure.repl)

apropos
demunge
dir
dir-fn
doc
find-doc
pst
root-cause
set-break-handler!
source
source-fn
stack-element-str
thread-stopper

And finally, we can see not only the documentation but the underlying source for any function accessible by the runtime: さらにすごいのは、実行環境からソースコードにアクセス可能なら、ドキュメンテーションのみならずソースコードを見ることができるということだ。

user=> (source dir)

(defmacro dir
  "Prints a sorted directory of public vars in a namespace
   名前空間で公開されているvarらの名前を整列して印字する"
  [nsname]
  `(doseq [v# (dir-fn '~nsname)]
     (println v#)))

As you go through this workshop, please feel free to examine the docstring and source for the functions you are using. このワークショップをやってみる中では、使うことになる関数のdocstringやソースコードを積極的に確認してみてほしい。Exploring the implementation of the Clojure library itself is an excellent way to learn more about the language and how it is used. Clojureライブラリの実装を探検してみることは、言語とその用法を学ぶための素晴らしい方法の一つだからだ。

It is also an excellent idea to keep a copy of the Clojure Cheatsheet open while you are learning Clojure. Clojureを学ぶ際に「Clojureチートシート」を傍らに置いておくというのもまた、素晴らしい方法である。 The cheetsheet categorizes the functions available in the standard library and is an invaluable reference. チートシートは標準ライブラリで使える関数らを分類しており、とても参考になる。

Now let's consider some Clojure basics to get you going.... ではいざ、Clojureの基礎を学んでいこう。

Clojure basics Clojureの基礎

def

When you are evaluating things at a REPL, it can be useful to save a piece of data for later. REPLで何か評価している時、データの一部を後で使うため保存しておきたいと思うことがあるはずだ。We can do this with def: 次のようにdefを使えばできる。

user=> (def x 7)
#'user/x

def is a special form that associates a symbol (x) in the current namespace with a value (7). defという特殊形式を使うと、現在の名前空間のシンボルをある値に紐づけできる。(シンボルはここではx、値は7だ。) This linkage is called a var. この紐づけはvarと呼ばれる。In most actual Clojure code, vars should refer to either a constant value or a function, but it's common to define and re-define them for convenience when working at the REPL. 実際のClojureコードでは普通、varは何らかの定数値や関数を参照しつづける。しかし、REPLで作業をする際には、varが指す値を定義し、繰り返し再定義することは普通に行われる。

Note the return value above is #'user/x - that's the literal representation for a var: #' followed by the namespaced symbol. 上で返り値として表示された#'user/xは、varのリテラル表現だ。varのリテラル表現はこのように、#'に続けて名前空間つきシンボルを置く。user is the default namespace. userはデフォルトの名前空間である。

Recall that symbols are evaluated by looking up what they refer to, so we can get the value back by just using the symbol: シンボルはそれが指し示す値へと評価されると言ったことを覚えているだろうか。それだから、単にシンボルを使うことで、それに紐づけた値を取り戻すことができる。

user=> (+ x x)
14

Printing 印字

One of the most common things you do when learning a language is to print out values. ある言語を学ぶ際に最も多用する操作の一つは、値を印字することだ。Clojure provides several functions for printing values: 印字のためにはClojureは以下の関数を提供する。

Human-Readable 人間可読 Machine-Readable 機械可読
With newline 改行あり println prn
Without newline 改行なし print pr

The human-readable forms will translate special print characters (like newlines and tabs) to their expected form and print strings without quotes. 人間可読形式は、(改行やタブなどの)特別な文字を一般的な形に変換するほか、文字列についてそれを囲むクォーテーションを印字しない。We often use println to debug functions or print a value at the REPL. REPLで関数をデバッグしたり値を表示する際に私達はよくprintlnを使う。printlntakes any number of arguments and interposes a space between each argument's printed value: printlnは任意個の引数を取り、印字されるそれらの間に空白を挟む。

user=> (println "What is this:" (+ 1 2))
What is this: 3

The println function has side-effects (printing) and return nil as a result. println関数は(印字するという)副作用を持ち、結果としてはnilを返す。

Note that "What is this:" above did not print the surrounding quotes and is not a string that the Reader could read again in the same way. 上で渡した"What is this:"のクォーテーションは印字されなかった。クォーテーションで囲まれていないため、リーダにこの文字列をそのまま読み取らせることはできない。For that purpose, use the machine-readable version prn: リーダに読み取れる形で印字したいなら、printlnに対応する機械可読なprnが使える。

user=> (prn "one\n\ttwo")
"one\n\ttwo"

Note that the printed result is a valid form that the Reader coud read again. ここで印字された形式は、リーダでそのまま読むために有効だ。Both human- and readable- printing functions are useful in different contexts. 人間可読な関数も機械可読な関数も、コンテキストによってそれぞれ有用な時がある。

Test your knowledge 理解の確認

  1. Using the REPL, compute the sum of 7654 and 1234. REPLを使って、7654と1234の和を計算してみなさい。
  2. Rewrite the following algebraic expression as a Clojure expression: ( 7 + 3 * 4 + 5 ) / 10. この代数の式をClojureの式になるように書き直してみなさい。
  3. Using REPL documentation functions, find the documentation for the rem and mod functions. REPLのドキュメンテーションの関数を使って、関数remとmodについて調べなさい。
  4. Using find-doc, find the function that prints the stack trace of the most recent REPL exception. find-doc関数を使って、REPLで発生した直近の例外のスタックトレースを表示する関数を探してみなさい。

原文: https://clojure.org/guides/learn/syntax