Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
7197 lines (5374 sloc) 523 KB
===============
The Pure Manual
===============
:著者: Albert Graf <Dr.Graef at t-online.de>
:訳者: cu39 <cu393uc at gmail.com>
:日付: |date|
.. Note: This document is formatted using docutils. The Makefile has rules
.. to build the documentation in html and pdf format. The latter needs TeX
.. and relies on the preamble.tex file to adjust the formatting. You might
.. have to edit preamble.tex to make this work with your local TeX
.. installation.
.. role:: dfn(strong)
.. default-role:: dfn
.. |date| date::
.. |time| date:: %H:%M
.. |GPL| replace:: GNU General Public License
.. |LGPL| replace:: GNU Lesser General Public License
.. |FDL| replace:: GNU Free Documentation License
.. _FDL: http://www.gnu.org/copyleft/fdl.html
.. _GPL: http://www.gnu.org/copyleft/gpl.html
.. _LGPL: http://www.gnu.org/copyleft/lgpl.html
.. _Pure Library Manual: purelib.html
.. Teach TeX how to hyphenate 'namespace'.
.. raw:: latex
\hyphenation{name-space}
\hyphenation{name-spaces}
Copyright (c) 2009-2010 by Albert Graf. This document is available under the
|FDL|_. Also see the Copying_ section for licensing information of the
software.
This manual describes the Pure programming language and how to invoke the Pure
interpreter program. To read the manual inside the interpreter, just type
``help`` at the command prompt. See the `Online Help`_ section for details.
このマニュアルは Pure プログラミング言語と Pure インタープリタプログラムを動かす方法を説明します。インタープリタを使っている最中にこのテキストを読むには、コマンドプロンプトでただ ``help`` とタイプして下さい。詳しくは `Online Help`_ セクションを参照。
There is a companion to this manual, the `Pure Library Manual`_ which contains
the description of the standard library operations. More information about
Pure can be found under the following URLs:
このマニュアルには `Pure Library Manual`_ という仲間もいて、標準ライブラリの働きを解説しています。以下のURLではさらに Pure に関する情報を見つけることができます:
* Pure website: http://pure-lang.googlecode.com
* Pure mailing list: http://groups.google.com/group/pure-lang
翻訳版に関する注意
この文書は pure.txt (r3346, Apr. 4, 2010) を日本語へ翻訳したものです。
原文は |FDL|_ ライセンスの下で公開されており、それに基づいてこの翻訳版も FDL の下で公開されています。
「〔」 [#]_ と「〕」 [#]_ に囲まれた語句は原典の表現を注記したものです。
.. [#] U+3014 始め亀甲括弧/LEFT TORTOISE SHELL BRACKET
.. [#] U+3015 終わり亀甲括弧/RIGHT TORTOISE SHELL BRACKET
.. contents::
.. sectnum::
Introduction
============
イントロダクション
Pure is a modern-style functional programming language based on term
rewriting. Pure programs are basically collections of equational rules used to
evaluate expressions in a symbolic fashion by reducing them to normal form. An
overview of the language can be found in the `Pure Overview`_ section below,
and subsequent sections discuss most language features in detail.
Pure は項書き換えを基礎とする現代的な関数型プログラミング言語です。Pure プログラムは基本的に等式ルールの集まりです。この等式は、式を記号的な方法で正規形へ還元して評価するのに使われます。言語の全体像は下にある `Pure Overview`_ セクションとそれに続くセクションにあり、言語機能のほとんどについて詳細に議論しています。
The Pure interpreter has an LLVM_ backend which JIT-compiles Pure programs to
machine code, hence programs run blazingly fast and interfacing to C modules
is easy, while the interpreter still provides a convenient, fully interactive
environment for running Pure scripts and evaluating expressions. You can also
compile your scripts to standalone executables if you prefer that.
Pure インタープリタは LLVM_ バックエンドを持っています。 LLVM は Pure プログラムをマシン語に JIT コンパイルします。そのためプログラムは激しく高速で、 C モジュールへ簡単に接続することができます。その一方でインタープリタは、 Pure で書かれたスクリプトや式を、完全にインタラクティブな使いやすい環境で走らせることができます。またお好みなら、スクリプトをスタンドアローンの実行ファイルにコンパイルすることもできます。
Pure programs (a.k.a. scripts) are just ordinary text files containing Pure
code. They must be encoded in UTF-8 (which subsumes 7 bit ASCII), other
encodings such as Latin-1 are not supported. A bunch of syntax highlighting
files and programming modes for various popular text editors are included in
the Pure sources. There's no difference between the Pure programming language
and the input language accepted by the interpreter, except that the
interpreter also understands some special commands when running in interactive
mode; see the `Interactive Usage`_ section for details.
Pure プログラム(またはスクリプト)は Pure コードを含んだ単なる普通のテキストファイルです。そのファイルは UTF-8 (7ビット ASCII をその一部に含む)でエンコードされなければならず、 Latin-1 のような他のエンコーディングはサポートされません。 Pure のソースには、有名なテキストエディタ用のシンタックスハイライト用ファイルやプログラミングモードがたくさん含まれています。 Pure 言語とインタープリタが許容する入力言語の間にほとんど違いはありませんが、対話モードで実行されているインタープリタはさらに特別なコマンドを理解します。詳しくは `Interactive Usage`_ を参照して下さい。
(In case you're wondering, the name "Pure" actually refers to the
adjective. But you can also write it as "PURE" and take this as a recursive
acronym for the "Pure Universal Rewriting Engine".)
(疑問を持つ方のために説明すると、 "Pure"という名前は実際には形容詞を表しています。しかしまた "PURE" と書いてもいいし、それを "Pure Universal Rewriting Engine" という再帰的頭字語と理解してもかまいません)
Invoking the Pure Interpreter
=============================
Pure インタープリタを起動する
The Pure interpreter is invoked as follows:
Pure インタープリタは以下のように起動されます::
pure [options ...] [script ...] [-- args ...]
pure [options ...] -x script [args ...]
Options
-------
オプション
The interpreter accepts various options which are described in more detail
below:
インタープリタは様々なオプションを許容します。詳細は以下の通り:
``-c``
Batch compilation.
バッチコンパイル。
``--ctags``, ``--etags``
Create a tags file in ctags (vi) or etags (emacs) format.
ctags (vi) か etags (emacs) フォーマットのタグファイルを生成する。
``--eager-jit``
Enable eager JIT compilation. This requires LLVM 2.7 or later, otherwise
this flag will be ignored.
eager JIT コンパイルを有効にする。この機能は LLVM 2.7 以上を必要とする。
存在しない場合このフラグは無視される。
``-fPIC``, ``-fpic``
Create position-independent code (batch compilation).
``-g``
Enable symbolic debugging.
シンボリックデバッグを有効にする。
``--help``, ``-h``
Print help message and exit.
ヘルプメッセージを表示して終了する。
``-i``
Force interactive mode (read commands from stdin).
対話モード(標準入力からコマンドを読む)を強制する。
``-I directory``
Add a directory to be searched for included source scripts.
インクルードするソーススクリプトを検索するディレクトリを追加する。
``-L directory``
Add a directory to be searched for dynamic libraries.
動的ライブラリを検索するディレクトリを追加する。
``-l libname``
Library to be linked in batch compilation.
バッチコンパイル時にリンクするライブラリを指定する。
``--noediting``
Disable command-line editing.
コマンドライン編集を無効にする。
``--noprelude``, ``-n``
Do not load the prelude.
preludeをロードしない。
``--norc``
Do not run the interactive startup files.
対話モード用のスタートアップファイルを実行しない。
``-o filename``
Output filename for batch compilation.
バッチコンパイル時の出力ファイル名を指定する。
``-q``
Quiet startup (suppresses sign-on message in interactive mode).
静かなスタートアップ(対話モードのサインオンメッセージを表示しない)。
``-T filename``
Tags file to be written by ``--ctags`` or ``--etags``.
``--ctags`` や ``--etags`` で出力されるタグファイル名を指定する。
``-u``
Do not strip unused functions in batch compilation.
バッチコンパイル時に使われていない関数が削除されるのを抑制する。
``-v[level]``
Set verbosity level. See below for details.
メッセージ表示レベル〔verbosity level〕を設定する。詳細は下部を参照。
``--version``
Print version information and exit.
バージョン情報を出力して終了。
``-w``
Enable compiler warnings about various dubious constructs and backward
compatibility issues.
様々な構造の曖昧さや後方互換性に関するコンパイラの警告メッセージを有効にする。
``-x``
Execute script with given command line arguments.
コマンドライン引数で渡されたスクリプトを実行する。
``--``
Stop option processing and pass the remaining command line arguments in
the ``argv`` variable.
オプションの処理を止め、残りのコマンドライン引数を ``argv`` 変数に渡す。
(Besides these, the interpreter also understands a number of other command
line switches for setting various code generation options; please see `Code
Generation Options`_ below for details.)
(これらに加えて、インタープリタは、コード生成オプションを設定するコマンドラインスイッチを他にもたくさん理解します。詳しくは下部 `Code Generation Options`_ を参照して下さい。
Overview of Operation
---------------------
動作の全体像
If any source scripts are specified on the command line, they are loaded and
executed, after which the interpreter exits. Otherwise the interpreter enters
the interactive read-eval-print loop, see `Running Interactively`_ below. You
can also use the -i option to enter the interactive loop (continue reading
from stdin) even after processing some source scripts.
コマンドラインでいかなるソーススクリプトが指定された場合でも、それは読み込まれて実行され、その後インタープリタは終了します。スクリプトが指定されない場合、インタープリタは read-eval-print ループの対話モードに入ります。下部 `Running Interactively`_ を参照して下さい。また -i オプションを使って、ソーススクリプトを処理した後でさえも続く対話ループ(標準入力から読み込みを続ける)に入ることもできます
Options and source files are processed in the order in which they are given on
the command line. Processing of options and source files ends when either the
-- or the -x option is encountered. The -x option must be followed by the name
of a script to be executed, which becomes the "main script" of the
application. In either case, any remaining parameters are passed to the
executing script by means of the global ``argc`` and ``argv`` variables,
denoting the number of arguments and the list of the actual parameter strings,
respectively. In the case of -x this also includes the script name as
``argv!0``. The -x option is useful, in particular, to turn Pure scripts into
executable programs by including a "shebang" like the following as the first
line in your main script. (This trick only works with Unix shells, though.)
オプションとソースファイルはコマンドラインで与えられた順番通りに処理されます。オプションやソースファイルスクリプトの処理は -- か -x オプションのいずれかが現れたところで終了します。 -x オプションの後には実行すべきスクリプトが続いている必要があり、そのファイルはアプリケーションの「メインスクリプト」となります。いずれの場合でも、後に続くあらゆるパラメータは ``argc`` 変数と ``argv`` 変数(それぞれ引数の数と、実際のパラメータ文字列を渡す)を通じて、実行されるスクリプトへ渡されます。 -x オプションの場合 ``argv!0`` として実行ファイル名を含みます。この -x オプションは、以下のように "shebang" をメインスクリプトの最初の行に置いてPureスクリプトを実行可能なプログラムにするとき特に便利です(ただしこの技は Unix シェルでしか機能しません)。
::
#!/usr/local/bin/pure -x
On startup, the interpreter also defines the ``version`` variable, which is
set to the version string of the Pure interpreter, and the ``sysinfo``
variable, which provides a string identifying the host system. These are
useful if parts of your script depend on the particular version of the
interpreter and the system it runs on. (Moreover, Pure 0.21 and later also
define the variable ``compiling`` which indicates whether the program is
executed in a batch compilation, see `Compiling Scripts`_ below.)
インタープリタは起動時に ``version`` 変数(Pure インタープリタのバージョン文字列がセットされる)と ``sysinfo`` 変数(ホストシステムを同定する文字列を提供)も定義します。これらの変数は、あなたのスクリプトのある一部が、インタープリタの特定のバージョンや、そのインタープリタが動作するシステムに依存している場合に役立つものです。(さらに Pure 0.21 以上は ``compiling`` 変数も定義します。この変数は、プログラムがバッチコンパイルで実行されるかどうかを示します。詳しくは下部 `Compiling Scripts`_ を参照)
If available, the prelude script prelude.pure is loaded by the interpreter
prior to any other definitions, unless the -n or --noprelude option is
specified. The prelude is searched for in the directory specified with the
PURELIB environment variable. If the PURELIB variable is not set, a
system-specific default is used. Relative pathnames of other source scripts
specified on the command line are interpreted relative to the current working
directory. In addition, the executed program may load other scripts and
libraries via a ``using`` declaration in the source, which are searched for in
a number of locations, including the directories named with the -I and -L
options; see the Declarations_ and `C Interface`_ sections for details.
もし prelude スクリプト(prelude.pure)が利用できる場合、インタープリタは他のあらゆる定義に先行してこれをロードします( -n や --noprelude が設定されない限り)。 prelude は PURELIB 環境変数で設定されたディレクトリから検索されます。もし PURELIB 変数が設定されていなければ、システム固有のデフォルトが使用されます。他のソーススクリプトの相対パス名がコマンドラインで指定されている場合、カレントワーキングディレクトリからの相対パスとして解釈されます。それに加え、実行されるプログラムが、ソース内の ``using`` 宣言を通じて他のスクリプトやライブラリをロードすることも可能です。このとき読み込まれるスクリプトやライブラリは、 -I と -L オプションで指定されるディレクトリを含め、たくさんの場所からロードされます。詳しくは Declarations_ と `C Interface`_ セクションを参照して下さい。
Compiling Scripts
-----------------
スクリプトのコンパイル
The interpreter compiles scripts, as well as definitions that you enter
interactively, automatically. This is done in an incremental fashion, as the
code is needed, and is therefore known as JIT (`just in time`) compilation.
Thus the interpreter never really "interprets" the source program or some
intermediate representation, it just acts as a frontend to the compiler,
taking care of compiling source code to native machine code before it gets
executed.
インタープリタはスクリプトだけでなく、あなたが対話的に入力する定義をも自動的にコンパイルします。このコンパイルはコードが必要となるにつれてインクリメント式に行われます。つまり JIT ( `just in time` )コンパイルとして知られているものです。このように、インタープリタはソースプログラムや他の何らかの中間的な表現〔some intermediate representation〕を本当に「解釈する」〔"interprets"〕ことはなく、単にコンパイラのフロントエンドとして振る舞い、ソースコードが実行される前にネイティブコードへとコンパイルする世話をしてくれます。
Pure's LLVM backend does "lazy JIT compilation" by default, meaning that each
function (global or local) is compiled no sooner than it is run for the first
time. With the --eager-jit option, however, it will also compile all other
(global or local) functions that may be called by the compiled function. (The
PURE_EAGER_JIT environment variable, when set to any value, has the same
effect, so that you do not have to specify the --eager--jit option each time
you run the interpreter.) Eager JIT compilation may be more efficient in some
cases (since bigger chunks of compilation work can be done in one go) and less
efficient in others (e.g., eager JITing may compile large chunks of code which
aren't actually called later, except in rare circumstances).
Pure の LLVM バックエンドはデフォルトでは「遅延 JIT コンパイル」〔"lazy JIT compilation"〕を行います。「遅延 JIT コンパイル」とは、(グローバルまたはローカルな)関数のそれぞれが、最初に実行される段階ではじめてコンパイルされることを意味します。しかし --eager-jit オプションを指定すれば、コンパイルされた関数から呼び出されるかもしれない他のすべての(ローカルまたはグローバルな)関数をもコンパイルします( PURE_EAGER_JIT 環境変数は、どんな値がセットされていても --eager-jit オプションと同じ効果を発揮するので、インタープリタを走らせるたびに毎回 --eager-jit オプションを指定する必要はなくなります)。先行 JIT コンパイル〔eager JIT compilation〕は、ある種のケースでは(比較的大きなコンパイル作業が一度に行われるので)より効果的でしょうし、別のケースでは効果的でなくなるでしょう(例えば、先行 JIT コンパイルが大きなコードの塊をコンパイルしても、実用上、それは稀な状況でしか呼ばれないものであるかもしれません)。
Note that the eager JIT mode is only available with LLVM 2.7 or later;
otherwise this option will be ignored.
先行 JIT コンパイルモードは LLVM 2.7 以降でのみ利用可能であることを忘れないで下さい。 2.6 以前だとこのオプションは無視されます。
It is also possible to compile your scripts to native code beforehand, using
the -c batch compilation option. This options forces the interpreter to
non-interactive mode (unless -i is specified as well, which overrides -c). Any
scripts specified on the command line are then executed as usual, but after
execution the interpreter takes a snapshot of the program and compiles it to
one of several supported output formats, LLVM assembler (.ll) or bitcode
(.bc), native assembler (.s) or object (.o), or a native executable, depending
on the output filename specified with -o. If the output filename ends in the
.ll extension, an LLVM assembler file is created which can then be processed
with the LLVM toolchain. If the output filename is just '-', the assembler
file is written to standard output, which is useful if you want to pass the
generated code to the LLVM tools in a pipeline. If the output filename ends in
the .bc extension, an LLVM bitcode file is created instead.
また -c バッチコンパイルオプションを使えば、あなたのスクリプトをあらかじめネイティブコードにコンパイルすることができます。このオプションはインタープリタに非対話モードを強制します( -i オプションを使った場合は別で、-c がオーバーライドされます)。コマンドラインで定義されたあらゆるオプションは通常通り実行されますが、実行後、インタープリタはプログラムのスナップショットを撮り、それを、サポートされている出力形式のいずれかへとコンパイルします。サポートされるのは LLVM アセンブラ(.ll)、ビットコード(.bc)、ネイティブアセンブラ(.s)、オブジェクト(.o)、ネイティブな実行ファイルで、 -o オプションで指定されたファイル名次第です。もし出力ファイル名が .ll 拡張子で終わっていたら LLVM アセンブラ用のファイルが作成され、そのファイルは LLVM のツールチェーンで処理できるものとなります。もし出力ファイルが '-' だけであれば、アセンブラファイルが標準出力に書かれます。これはパイプを通じて LLVM ツールにコードを渡したいときに便利です。もし出力ファイル名が .bc で終わっていたら、 LLVM のビットコードファイルが作られます。
The .ll and .bc formats are supported natively by the Pure interpreter, no
external tools are required to generate these. If the target is an .s, .o or
executable file, the Pure interpreter creates a temporary bitcode file on
which it invokes the LLVM tools opt and llc to create a native assembler file,
and then uses gcc to assemble and link the resulting program (if requested).
You can also specify additional libraries to be linked into the executable
with the -l option. If the output filename is omitted, it defaults to
``a.out`` (``a.exe`` on Windows).
Pure インタープリタは .ll 形式と .bc 形式をネイティブにサポートしており、外部ツールに頼らずそれらを出力できます。もしターゲットが .s か .o か実行可能ファイルであった場合、 Pure インタープリタは一時的なビットコードファイルを作成し、それに対して LLVM ツールの opt と llc を実行してネイティブなアセンブラファイルを作成します。その後(必要があれば) gcc を使って最終的なプログラムをコンパイル&リンクします。 -l オプションを使って、実行ファイルにリンクすべき追加ライブラリを定義することも可能です。もし出力ファイル名を省略した場合、出力ファイル名は ``a.out`` (Windows では ``.exe`` )となります。
The -c option provides a convenient way to quickly turn a Pure script into a
standalone executable which can be invoked directly from the shell. One
advantage of compiling your script is that this eliminates the JIT compilation
time and thus considerably reduces the startup time of the program. Another
reason to prefer a standalone executable is that it lets you deploy the
program on systems without a full Pure installation (usually only the runtime
library is required on the target system). On the other hand, compiled scripts
also have some limitations, mostly concerning the use of the built-in ``eval``
function. Please see the `Batch Compilation`_ section for details.
-c オプションは Pure スクリプトをスタンドアローンな実行ファイルへと素早く変える便利な方法です。この実行ファイルはシェルから直接実行できます。スクリプトをコンパイルすることの利点のひとつは、 JIT コンパイルにかかる時間を排除し、プログラムの起動時間をかなり短縮できることにあります。スタンドアローンな実行ファイルを好むべきもう一つの理由は、 Pure をフルインストールしなくてもプログラムをシステム上に配置できる点です(しばしば対象システムに合わせたラインタイムライブラリだけは必要になります)。その一方で、コンパイルされたスクリプトにはいくつかの制限があります。最も重大なのは、組み込み ``eval`` 関数の使用に関する制限です。詳しくは `Batch Compilation`_ セクションを参照して下さい。
The -v64 (or -v0100) verbosity option can be used to have the interpreter
print the commands it executes during compilation, see `Verbosity and
Debugging Options`_ below. When creating an object file, this also prints the
suggested linker command (including all the dynamic modules loaded by the
script, which also have to be linked in to create a working executable), to
which you only have to add the options describing the desired output file.
-64 (あるいは -v0100)饒舌〔verbosity〕オプションを指定すると、インタープリタがコンパイル中に実行されるコマンドを出力させることができます。下部 `Verbosity and Debugging Options`_ を参照して下さい。オブジェクトファイルを作成している最中は、示唆されたリンカコマンドを出力します(スクリプトによって動的にロードされるモジュールのすべても含まれます。それらは実行ファイルを作成するためにリンクされる必要があるものです)が、そのためにあなたがしなければならないのは、求めている出力ファイルを説明するオプションを付加することだけです。
Tagging Scripts
---------------
スクリプトへのタグ付け
Pure programs often have declarations and definitions of global symbols
scattered out over many different source files. The --ctags and --etags
options let you create a tags_ file which allows you to quickly locate these
items in text editors such as vi and emacs which support this feature.
Pure で書かれたプログラムは様々なグローバルシンボルの宣言や定義を持ちますが、それらはしばしば別のソースファイルへ数多くちりばめられます。 --ctags と --etags オプションを使うと tags_ ファイルを作成できますが、これを使うと、そうしたアイテムをテキストエディター(vi や emacs など、この機能をサポートするもの)内で素早く配置することができます。
.. _tags: http://en.wikipedia.org/wiki/Ctags
If --ctags or --etags is specified, the interpreter enters a special mode in
which it only parses source files without executing them and collects
information about the locations of global symbol declarations and definitions.
The collected information is then written to a tags file in the ctags or etags
format used by vi and emacs, respectively. The desired name of the tags file
can be specified with the -T option; it defaults to ``tags`` for --ctags and
``TAGS`` for --etags (which matches the default tags file names used by vi and
emacs, respectively).
もし --ctags か --etags が定義されている場合、インタープリタは特別モードになり、ソースファイルを実行せず、解析だけを行ってグローバルシンボルの宣言と定義を収集します。その後、集められた情報は tags ファイル内に ctags か etags フォーマット(vi と emacs で使われるフォーマット)でそれぞれ書き込まれます。 -T オプションを使って tags ファイルにお望みの名前をつけることもできます。デフォルトの名前は、 --ctags は ``tags`` 、 --etags では ``TAGS`` となります(それぞれ vi と emacs がデフォルトとして検索する tags ファイル名)。
The tags file contains information about the global constant, variable, macro,
function and operator symbols of all scripts specified on the command line, as
well as the prelude and other scripts included via a ``using`` clause. Tagged
scripts which are located in the same directory as the tags file (or,
recursively, in one of its subdirectories) are specified using relative
pathnames, while scripts outside this hierarchy (such as included scripts from
the standard library) are denoted with absolute pathnames. This scheme makes
it possible to move an entire directory together with its tags file and have
the tags information still work in the new location.
tags ファイルには、コマンドラインで指定されたスクリプトファイル、 prelude 、 ``using`` 節で宣言された他のインクルードスクリプト内にある、グローバルな定数、変数、マクロ、関数、演算子シンボルの情報が含まれています。 tags ファイルと同じディレクトリ(または、再帰的に、サブディレクトリ)にあるタグ付けされたスクリプトは、相対パスで定義されます。それに対して、この階層構造の外にあるスクリプト(例えば標準ライブラリからインクルードされたスクリプト)は絶対パスで示されます。この方式により、 tags ファイルも含めてディレクトリ全体を他の場所に移動しても、 tags ファイルの情報は同じように機能します。
Running Interactively
---------------------
対話的に実行する
If the interpreter runs in interactive mode, it repeatedly prompts you for
input (which may be any legal Pure code or some special interpreter commands
provided for interactive usage), and prints computed results. This is also
known as the `read-eval-print` loop and is described in much more detail in
the `Interactive Usage`_ section. To exit the interpreter, just type the
``quit`` command or the end-of-file character (``^D`` on Unix) at the
beginning of the command line.
インタープリタが対話モードで実行されている場合、インタープリタは繰り返しあなたに入力を促し(入力は Pure のコードでも、対話モード専用のコマンドでもかまいません)、計算結果を表示します。これは `read-eval-print` ループとしても知られ、 `Interactive Usage`_ セクションでより詳細に説明されます。インタープリタを終了するには、ただ ``quit`` コマンドを打ち込むか、コマンドラインの先頭で end-of-file 文字(Unix では ``^D`` )を入力します。
The interpreter may also source a few additional interactive startup files
immediately before entering the interactive loop, unless the --norc option is
specified. First .purerc in the user's home directory is read, then .purerc in
the current working directory. These are ordinary Pure scripts which can be
used to provide additional definitions for interactive usage. Finally, a .pure
file in the current directory (containing a dump from a previous interactive
session) is loaded if it is present.
インタープリタは他にも対話モード用の追加的な初期ファイルをたどります。これは対話ループに入る直前に行われますが、 --norc オプションが設定された場合は実行されません。まず最初にユーザのホームディレクトリにある .purerc ファイルが読み込まれ、次にカレントワーキングディレクトリにある .purerc が読み込まれます。通常これらのファイルは Pure スクリプトで、対話モード用の追加定義を行うために使われます。最後に、カレントディレクトリの .pure ファイル(直前の対話モードセッションのダンプを含む)が(もしあれば)読み込まれます。
When the interpreter is in interactive mode and reads from a tty, unless the
--noediting option is specified, commands are usually read using readline(3)
or some compatible replacement, providing completion for all commands listed
under `Interactive Usage`_, as well as for symbols defined in the running
program. When exiting the interpreter, the command history is stored in
~/.pure_history, from where it is restored the next time you run the
interpreter.
インタープリタが対話モードかつ tty から読まれている場合、 --noediting オプションが指定されていなければ、コマンドは通常 readline(3) かその互換代替を使って読み込まれます。 `Interactive Usage`_ 以下にリストされている全コマンドと、実行中のプログラムで定義されているシンボルの補完機能を使うことができます。インタープリタを終了するとき、コマンド履歴が ~/.pure_history ファイルに保存され、次回インタープリタが起動したときにこのファイルから履歴を復旧します。
As of Pure 0.22, the interpreter also provides a simple source level debugger
when run in interactive mode, see Debugging_ for details. To enable the
interactive debugger, you need to specify the -g option when invoking the
interpreter. This option causes your script to run *much* slower and also
disables tail call optimization, so you should only use this option if you
want to run the debugger.
Pure 0.22 以降では、インタープリタの対話モードはシンプルなソースレベルデバッガも提供しています。詳しくは Debugging_ セクションを参照して下さい。対話デバッガを有効にするには、インタープリタ起動時に -g オプションを指定する必要があります。このオプションはあなたのスクリプトの実行を *かなり* 遅くし、また末尾呼び出しの最適化を無効にします。そのためこのオプションはデバッガを使いたいときだけ指定する方がよいでしょう。
Verbosity and Debugging Options
-------------------------------
饒舌さとデバッグオプション
The -v option is useful for debugging the interpreter, or if you are
interested in the code your program gets compiled to. The level argument is
optional; it defaults to 1. Seven different levels are implemented at this
time (one more bit is reserved for future extensions). For most purposes, only
the first two levels will be useful for the average Pure programmer; the
remaining levels are most likely to be used by the Pure interpreter
developers.
-v オプションはインタープリタでデバッグを行う際や、あなたのプログラムがコンパイルされた結果のコードに興味がある場合に役立ちます。レベル引数を指定してもしなくてもかまいません。デフォルトは 1 です。今のところ 7 段階のレベルが実装されています(もう 1 ビットが将来の拡張用に予約されています)。平均的な Pure プログラマーのたいがいの用途では、最初の 2 レベルで充分役に立つでしょう。残りのレベルは Pure インタープリタ開発者が使うようなものです。
1 (0x1, 001)
denotes echoing of parsed definitions and expressions.
定義と式の解析結果をエコーすることを示します。
2 (0x2, 002)
adds special annotations concerning local bindings (de Bruijn indices,
subterm paths; this can be helpful to debug tricky variable binding
issues).
ローカル束縛に関する特別な注釈を付加します(de Bruijn インデックス、下位項パス〔subterm paths〕)。これはトリッキーな変数束縛をデバッグする際に役立ちうるものです。
4 (0x4, 004)
adds descriptions of the matching automata for the left-hand sides of
equations (you probably want to see this only when working on the guts of
the interpreter).
等式左辺への自動マッチングの説明を付加します(これを見たいと思うのは、インタープリタの内蔵部について作業しているときだけでしょう)。
8 (0x8, 010)
dumps the "real" output code (LLVM assembler, which is as close to the
native machine code for your program as it gets; you definitely don't want
to see this unless you have to inspect the generated code for bugs or
performance issues).
「本当の」出力コードをダンプします(LLVM アセンブラのことです。このコードはあなたのプログラムがネイティブな機械語になったものとほぼ同じです。この出力を見たいと思うのは、バグやパフォーマンスの問題のため生成コードを精査する必要がある場合くらいでしょう)。
16 (0x10, 020)
adds debugging messages from the bison(1) parser; useful for debugging the
parser.
bison(1) からのデバッグメッセージを付加します。構文解析器〔パーサー〕をデバッグするのに役立ちます。
32 (0x20, 040)
adds debugging messages from the flex(1) lexer; useful for debugging the
lexer.
flex レキサーからのデバッグメッセージを付加します。字句解析器〔レキサー〕をデバッグするのに役立ちます。
64 (0x40, 0100)
turns on verbose batch compilation; this is useful if you want to see
exactly which commands get executed during batch compilation (-c).
饒舌なバッチコンパイルを有効にします。バッチコンパイル(-c)中にどのコマンドが実行されているのか正確に見たいときに役立ちます。
These values can be or'ed together, and, for convenience, can be specified in
either decimal, hexadecimal or octal. Thus 0xff or 0777 always gives you full
debugging output (which isn't likely to be used by anyone but the Pure
developers). Some useful flag combinations for experts are (in octal) 007
(echo definitions along with de Bruijn indices and matching automata), 011
(definitions and assembler code) and 021 (parser debugging output along with
parsed definitions).
これらの値をまとめて or 接続することができます。また、便利なことに、10進数、16進数、8進数のいずれでも指定することができます。したがって 0xff や 0777 を指定すると常に完全なデバッグ出力を得ることができます(使うのは Pure 開発者くらいでしょうが)。エキスパートにとって役立ちそうなフラグの組み合わせは、(8進数で) 007 (定義、de Bruijn インデックス、自動マッチングをエコー)、 011 (定義とアセンブラコード)、 021 (パーサーのデバッグ出力、解析された定義)です。
Note that the -v option is only applied after the prelude has been loaded. If
you want to debug the prelude, use the -n option and specify the prelude.pure
file explicitly on the command line. Verbose output is also suppressed for
modules imported through a ``using`` clause. As a remedy, you can use the
interactive ``show`` command (see the `Interactive Usage`_ section) to list
definitions along with additional debugging information.
-v オプションが適用されるのは prelude を読み込んだ後からであることを忘れないで下さい。もし prelude をデバッグしたい場合、コマンドラインから -n オプションで prelude.pure ファイルを明示指定して下さい。 ``using`` 節を通じてインポートされるモジュールに対しても饒舌な出力は抑制されます。そこでも饒舌に出力させたいなら、対話モードの ``show`` コマンド( `Interactive Usage`_ 節を参照)を使い、定義とともに追加のデバッグ情報をリストすることができます。
Code Generation Options
-----------------------
コード生成オプション
Besides the options listed above, the interpreter also understands some
additional command line switches and corresponding environment variables to
control various code generation options. The options take the form ``--opt``
and ``--noopt``, respectively, where ``opt`` denotes the option name (see
below for a list of supported options). By default, these options are all
enabled; ``--noopt`` disables the option, ``--opt`` reenables it. In addition,
for each option ``opt`` there is also a corresponding environment variable
``PURE_NOOPT`` (with the option name in uppercase) which, when set, disables
the option by default. (Setting this variable to any value will do, the
interpreter only checks whether the variable exists in the environment.)
上でリストされたオプションに加えて、インタープリタは、追加的なコマンドラインスイッチとそれに対応する環境変数をもう少し理解します。これらは様々なコード生成オプションを制御するためのもので、それぞれ ``--opt`` と ``--noopt`` という形式をとります。このとき ``opt`` 部分はオプション名を示しています(サポートされるオプションは下にあるリストを参照して下さい)。デフォルトでは、これらのオプションの全てが有効です。 ``--noopt`` はオプションを無効にし、 ``--opt`` はそれを再び有効にします。加えて、各オプション ``opt`` には、それぞれ対応する環境変数 ``PURE_NOOPT`` (OPT 部分に大文字のオプション名を指定する)があります。これが設定されている場合、そのオプションはデフォルトで無効となります(変数にいかなる値が設定されていても動作します。インタープリタは環境にその変数が存在するかどうかだけをチェックします)。
For instance, the ``checks`` option controls stack and signal checks. Thus
``--nochecks`` on the command line disables the option, and setting the
``PURE_NOCHECKS`` environment variable makes this the default, in which case
you can use ``--checks`` on the command line to reenable the option.
例えば、 ``checks`` オプションはスタックとシグナルのチェックを制御します。したがって ``--nochecks`` をコマンドラインで指定すると、このオプションは無効となります。また、環境変数 ``PURE_NOCHECKS`` を設定した場合は無効な状態をデフォルトとします。この場合、コマンドラインで ``--checks`` を指定すると、オプションが再び有効となるわけです。
Each code generation option can also be used as a *pragma* (compiler
directive) in source code so that you can control it on a per-rule basis. The
pragma must be on a line by itself, starting in column 1, and takes the
following form (using ``--nochecks`` as an example):
各コード生成オプションは、ソース内で *プラグマ* (コンパイラディレクティブ)として使うこともでき、ルール単位でオプションを制御することができます。プラグマはそれだけで単独行を占める必要があり、行の1文字目から始まり、次のような形式をとります(例として ``--nochecks`` を使います::
#! --nochecks // line-oriented comment may go here
#! --nochecks // ここに一行コメントを書けます
Currently, the following code generation options are recognized:
今のところ、次のコード生成オプションが認識されます:
``--checks``, ``--nochecks``
Enable or disable various extra stack and signal checks. By default, the
interpreter checks for stack overflows (if the ``PURE_STACK`` environment
variable is set) and pending signals on entry to every function, see
`Stack Size and Tail Recursion`_ and `Handling of Asynchronous Signals`_
for details. This is needed to catch these conditions in a reliable way,
so we recommend to leave this enabled. However, these checks also make
programs run a little slower (typically some 5%, YMMV). If performance is
critical then you can disable the checks with the ``--nochecks``
option. (Even then, a minimal amount of checking will be done, usually on
entry to every global function.)
``--checks``, ``--nochecks``
様々な追加スタックチェックと追加シグナルチェックを有効・無効にします。デフォルトでは、インタープリタがチェックするのはスタックオーバーフロー( ``PURE_STACK`` 環境変数が設定されている場合)と、関数へのエントリー時の保留シグナルです。詳しくは `Stack Size and Tail Recursion`_ と `Handling of Asynchronous Signals`_ を参照して下さい。Thisはtheseを確実な方法でキャッチするために必要なもので、thisを有効なままにしておくことを推奨します。しかし、これらのチェックはプログラムの実行速度を少し遅くします(典型的には 5% ほどですが、異なる意見もあります)。パフォーマンスが非常に重要ならば、 ``--nochecks`` オプションを使ってこのチェックを無効にすることができます(その場合でも、通例としてグローバル関数へのエントリー時に、最小限のチェックが行われます)。
``--fold``, ``--nofold``
Enable or disable constant folding in the compiler frontend. This means
that constant expressions involving int and double values and the usual
arithmetic and logical operations on these are precomputed at compile
time. (This is mostly for cosmetic purposes; the LLVM backend will perform
this optimization anyway when generating machine code.) For instance:
``--fold``, ``--nofold``
コンパイラフロントエンドでの定数の折りたたみを有効・無効にします。 int と double の値を持つ定数式および、それらに対する算術・論理演算を、コンパイル時に事前計算します(これはほぼ表面を取り繕うためだけのものです。いずれにしても LLVM バックエンドはマシンコード生成時にこの最適化を実施します)。例えば::
> foo x = 2*3*x;
> show foo
foo x = 6*x;
Disabling constant folding in the frontend causes constant expressions to
be shown as you entered them:
フロントエンドでの定数折りたたみを無効にすると、あなたが入力したままの形で定数式が表示されます::
> #! --nofold
> bar x = 2*3*x;
> show bar
bar x = 2*3*x;
``--tc``, ``--notc``
Enable or disable tail call optimization (TCO). TCO is needed to make
tail-recursive functions execute in constant stack space, so we recommend
to leave this enabled. However, at the time of this writing LLVM's TCO
support is still bug-ridden on some platforms, so the ``--notc`` option
allows you to disable it. (Note that TCO can also be disabled when
compiling the Pure interpreter, in which case these options have no
effect; see the installation documentation for details.)
``--tc``, ``--notc``
末尾呼び出し最適化〔tail call optimization (TCO)〕を有効・無効にします。 TCO は一定のスタック領域内で末尾再帰関数を実行できるようにするため必要なものであり、このオプションを有効なままにすることを推奨します。しかし、このドキュメントを書いている段階では、 LLVM の TCO サポートはいくつかのプラットフォーム上でまだバグが多く残っている状態なので、 ``--notc`` オプションを無効にすることが可能なままにしてあります( TCO は Pure インタープリタをコンパイルするときも無効にできます。その場合、このオプションは効果を持ちません。詳しくはインストールドキュメントを参照して下さい)。
Besides these, there's also a special pragma for telling the batch compiler
about "required" functions:
これらに加えて、 "required" な関数をバッチコンパイラに伝えるための特別なプラグマもあります:
``--required fun``
Inform the batch compiler (cf. `Compiling Scripts`_) that the given
function symbol ``fun`` should never be stripped from the program. This
is useful, e.g., if a function is never called explicitly but only through
``eval``. Adding a ``--required`` pragma for the function then makes sure
that the function is always linked into the program.
``--required fun``
バッチコンパイラ(cf. `Compiling Scripts`_ )に対して、与えられた関数シンボル ``fun`` をプログラムから決して取り除かないよう伝えます。このオプションが便利なのは、例えば、ある関数が明示的に呼ばれることは一度もないが、 ``eval`` を通して呼ばれることがある場合です。その関数のために ``--required`` プラグマを追加してやると、その関数が常に確実にプログラムへリンクされるようになります。
Note that the ``--required`` pragma can only be used in source code, there's
no command line option for it. An example showing how to use this option can
be found in the `Batch Compilation`_ section.
``--required`` プラグマはソースコード内だけでしか使えないことに注意して下さい。コマンドラインオプションは存在しません。このオプションの使い方を示した例は `Batch Compilation`_ セクションにあります。
Startup Files
-------------
スタートアップファイル
The interpreter may source various files during its startup. These are:
インタープリタは起動時に様々なファイルを読み込みます。以下の通り:
~/.pure_history
Interactive command history.
対話コマンドの履歴。
~/.purerc, .purerc, .pure
Interactive startup files. The latter is usually a dump from a previous
interactive session.
prelude.pure
Standard prelude. If available, this script is loaded before any other
definitions, unless -n was specified.
標準prelude。prelude.pureがある場合、他のあらゆる定義に先行してロードされます(-n や --noprelude が設定されない限り)
Environment
-----------
環境
Various aspects of the interpreter can be configured through the following
shell environment variables:
以下のシェル環境変数を通じて、インタープリタの様々な側面を設定することができます:
BROWSER
If the PURE_HELP variable is not set (see below), this specifies a
colon-separated list of browsers to try for reading the online
documentation. See http://catb.org/~esr/BROWSER/.
もし PURE_HELP 変数(下を参照)が設定されていない場合、この変数がコロンで区切られたブラウザのリストを定義します。そこの含まれるブラウザはオンラインドキュメントを読む際に順に試されます。 http://catb.org/~esr/BROWSER/ を参照。
PURELIB
Directory to search for library scripts, including the prelude. If PURELIB
is not set, it defaults to some location specified at installation time.
ライブラリスクリプト(prelude を含む)を検索するディレクトリです。もし PURELIB が設定されていない場合、インストール時に定義された場所をデフォルトとします。
PURE_EAGER_JIT
Enable eager JIT compilation (same as ``--eager-jit``), see `Compiling
Scripts`_ for details.
先行(JIT)コンパイルを有効にします(``--eager-jit`` と同様)。詳しくは `Compiling Scripts`_ を参照。
PURE_HELP
Command used to browse the Pure manual. This must be a browser capable of
displaying html files. Default is w3m(1).
Pureマニュアルを読むのに使うコマンドを設定します。このコマンドはHTMLファイルを表示できるものでなければいけません。デフォルトは w3m(1) です。
PURE_INCLUDE
Additional directories (in colon-separated format) to be searched for
included scripts.
インクルードするスクリプトファイルを探す追加ディレクトリです(コロン区切りフォーマット)。
PURE_LIBRARY
Additional directories (in colon-separated format) to be searched for
dynamic libraries.
動的ライブラリを探す追加ディレクトリです(コロン区切りフォーマット)。
PURE_MORE
Shell command to be used for paging through output of the show command,
when the interpreter runs in interactive mode.
インタープリタが対話モードで実行されているとき、 show コマンドの出力のページングに使われるコマンドです。
PURE_PS
Command prompt used in the interactive command loop ("> " by default).
対話式のコマンドループで使われるコマンドプロンプトです(デフォルトは "> ")。
PURE_STACK
Maximum stack size in kilobytes (default: 0 = unlimited).
最大スタックサイズをキロバイト単位で設定します(デフォルト: 0 = 制限なし)。
(Besides these, the interpreter also understands a number of other environment
variables for controlling various code generation options; please see `Code
Generation Options`_ above for details.)
これらに加え、インタープリタは他にもたくさんの環境変数を理解するので、様々なコード生成オプションをコントロールできます。詳しくは上部 `Code Generation Options`_ を参照して下さい。
Pure Overview
=============
Pureの全体像
Pure is a fairly simple yet powerful language. Programs are basically
collections of rewriting rules and expressions to be evaluated. For
convenience, it is also possible to define global variables and constants, and
for advanced uses Pure offers macro functions as a kind of preprocessing
facility. These are all described below and in the following sections.
Pureは適度にシンプルであながらパワフルでもある言語です。プログラムは基本的に、書き換えルールと、評価されるべき式の集まりです。便宜のため、グローバル変数と定数を定義することもできます。またもっと高度な使用のため、Pureはマクロ関数も提供します as a kind of preprocessing facility. これらのすべては下のセクションとそれに続くセクションで説明されます。
Here's a first example which demonstrates how to define a simple recursive
function in Pure, entered interactively in the interpreter (note that the
'``>``' symbol at the beginning of each input line is the interpreter's
default command prompt):
これはPureでシンプルな再帰関数を定義する方法を示す最初のサンプルで、インタープリタへ対話的に入力されています(各入力行の先頭にある '``>``' 記号がインタープリタのデフォルトプロンプトだということに注意して下さい)::
> // my first Pure example
> fact 0 = 1;
> fact n::int = n*fact (n-1) if n>0;
> let x = fact 10; x;
3628800
Lexical Matters
---------------
レキシカルな要素
Pure is a free-format language; whitespace is insignificant, except if it
serves to delimit other symbols. Hence, as shown above, definitions and
expressions at the toplevel have to be terminated with a semicolon, even in
interactive mode.
Pure は自由形式〔free-format〕の言語です。ホワイトスペースは、他のシンボルの境界として機能する場合を除き、重要ではありません。したがって、上で示した通り、たとえ対話モードであっても、最上位にある定義と式はセミコロンで終わる必要があります。
Comments have the same syntax as in C++ (using ``//`` for line-oriented and
``/* ... */`` for multiline comments; the latter may not be nested). Lines
beginning with ``#!`` are treated as comments, too; as already discussed
above, on Unix-like systems this allows you to add a "shebang" to your main
script in order to turn it into an executable program.
コメントは C++ と同じ構文を持っています( ``//`` を一行コメントに使い、 ``/* ... */`` を複数行コメントに使用。後者はネスト可能)。 ``#!`` で始まる行もまたコメント扱いで、すでに上で議論した通り、 Unix-like なシステム上では、メインスクリプトにこの "shebang" を追加して実行可能なプログラムへと変えることができます。
There are a few reserved keywords which cannot be used as identifiers:
識別子に使うことができない予約語がいくつかあります::
case const def else end extern if infix infixl infixr let namespace
nonfix of otherwise outfix postfix prefix private public then using
when with
The customary notations for identifiers, numbers and strings are all
provided. In addition, Pure also allows you to define your own operator
symbols. Pure fully supports Unicode, so that you can write your programs in
almost any language and make good use of the special symbols in the Unicode
character set, provided that you encode your scripts in UTF-8. To keep this
simple, besides the ASCII punctuation characters, Pure also considers the
following code points in the Unicode repertoire as punctuation: U+00A1 through
U+00BF, U+00D7, U+00F7, and U+20D0 through through U+2BFF. This comprises the
special symbols in the Latin-1 repertoire, as well as the Combining
Diacritical Marks for Symbols, Letterlike Symbols, Number Forms, Arrows,
Mathematical Symbols, Miscellaneous Technical Symbols, Control Pictures, OCR,
Enclosed Alphanumerics, Box Drawing, Blocks, Geometric Shapes, Miscellaneous
Symbols, Dingbats, Miscellaneous Mathematical Symbols A, Supplemental Arrows
A, Supplemental Arrows B, Miscellaneous Mathematical Symbols B, Supplemental
Mathematical Operators, and Miscellaneous Symbols and Arrows. This should
cover almost everything you'd ever want to use in an operator symbol. All
other extended Unicode characters are effectively treated as "letters" which
can be used as identifier constituents.
識別子、数値、文字列の慣習的な表記法はすべて提供されています。加えて、Pureではあなたが自分で演算子を定義することも許されます。PureはUnicodeをフルサポートしており、(ほとんど)あらゆる言語でプログラムを書くことができ、Unicode文字セットに含まれる■特別な■記号を活用することができます(スクリプトがUTF-8でエンコードされていることが必要)。このシンプルさを保つため、ASCIIの句読点文字に加えて、PureはUnicodeレパートリーが含む以下のコードポイントを句読点とみなします: U+00A1 から U+00BF まで、 U+00D7、 U+00F7、 U+20D0 から U+2BFF まで。これは Latin-1 レパートリーの特別記号や以下の記号を含んでいます: Combining Diacritical Marks for Symbols, Letterlike Symbols, Number Forms, Arrows, Mathematical Symbols, Miscellaneous Technical Symbols, Control Pictures, OCR, Enclosed Alphanumerics, Box Drawing, Blocks, Geometric Shapes, Miscellaneous Symbols, Dingbats, Miscellaneous Mathematical Symbols A, Supplemental Arrows A, Supplemental Arrows B, Miscellaneous Mathematical Symbols B, Supplemental Mathematical Operators, and Miscellaneous Symbols and Arrows 。あなたが演算子シンボルとして使いたいと願うもののほぼすべてをカバーしているでしょう。その他の Unicode 拡張文字は事実上「文字」として扱われ、識別子の構成要素にすることができます。
Definitions and Expression Evaluation
-------------------------------------
定義と、式の評価
On the surface, Pure is quite similar to other modern functional languages
like Haskell_ and ML_. But under the hood it is a much more dynamic language,
more akin to Lisp. In particular, Pure is dynamically typed, so functions can
be fully polymorphic and you can add to the definition of an existing function
at any time. For instance, we can extend the example above to make the
``fact`` function work with floating point numbers, too:
表面的には、Pureは Haskell_ や ML_ のような他の現代的関数型言語とよく似ています。しかしフードの下ではもっと動的な言語で、より Lisp に近くなります。特に、Pureは動的に型を決定するので、関数はとても多態的になることができますし、あなたは既存の関数に定義を追加することができます。例えば、上で例に出した例を拡張して、 ``fact`` 関数が浮動小数点数を扱えるようにすることも可能です::
> fact 0.0 = 1.0;
> fact n::double = n*fact (n-1) if n>0;
> fact 10.0;
3628800.0
> fact 10;
3628800
Note the ``n::double`` construct on the left-hand side of the second
equation, which means that the equation is only to be applied for (double
precision) floating point values ``n``. This construct is also called a "type
tag" in Pure parlance, which is actually a simple form of pattern matching
(see below). Similarly, our previous definition at the beginning of this
section employed the ``int`` tag to indicate that the ``n`` parameter is an
integer value. The ``int`` and ``double`` types are built into the Pure
language, but it is also possible to introduce your own type tags for
user-defined data structures. This will be explained in more detail under
`Type Tags`_ in the `Rule Syntax`_ section below.
2番目の等式の左辺側にある ``n::double`` 構造に注意して下さい。これはこの等式が(倍精度の)浮動小数点数の値をもつ ``n`` だけに適用されるものであることを意味しています。この構造はPure用語で「型タグ」とも呼ばれるもので、実際、パターンマッチングのシンプルな形式でもあります(下部参照)。同じように、このセクション冒頭の定義では ``int`` タグを使って ``n`` パラメータが整数値であることを示しました。 ``int`` 型と ``double`` 型はPure言語に組み込まれているものですが、ほかにユーザ定義のデータ構造のための独自の型タグをあなたが導入することも可能です。それについての詳細は下部 `Rule Syntax`_ セクション内 `Type Tags`_ 部で説明します。
Expressions are generally evaluated from left to right, innermost expressions
first, i.e., using call by value semantics. Pure also has a few built-in
special forms (most notably, conditional expressions, the short-circuit
logical connectives ``&&`` and ``||``, the sequencing operator ``$$``, the
lazy evaluation operator ``&``, and the ``quote``) which take some or all of
their arguments unevaluated, using call by name.
式は一般に左から右へ、内側の式ほど先に評価されます。すなわちcall by value semanticsを使っています。Pureはまた、いくつかの組み込み特別形を持っています(特に注目すべきは条件式に関するもので、短絡論理結合子 ``&&`` と ``||`` 、継起演算子〔sequencing operator〕 ``$$`` 、遅延評価演算子 ``&`` 、そして ``quote`` )。これらはいくつかの、あるいはすべての引数を未評価なまま持ち、call by name方式を使います。
Like in Haskell and ML, functions are often defined by pattern matching, i.e.,
the left-hand side of a definition is compared to the target expression,
binding the variables in the pattern to their actual values accordingly:
Haskell や ML のように、関数はしばしばパターンマッチングによって評価されます。つまり、定義の左辺は対象となる式と比較され、変数がパターン中の実際の値に対応するかたちで束縛されます::
> foo (bar x) = x-1;
> foo (bar 99);
98
Due to its term rewriting semantics, Pure goes beyond most other functional
languages in that it can do symbolic evaluations just as well as "normal"
computations:
書き換えセマンティクスにより、「普通の」計算だけでなく記号代数的評価を行えるという点で、Pureは他の関数言語の一歩先を行っています::
> square x = x*x;
> square 4;
16
> square (a+b);
(a+b)*(a+b)
Leaving aside the built-in support for some common data structures such as
numbers and strings, all the Pure interpreter really does is evaluate
expressions in a symbolic fashion, rewriting expressions using the equations
supplied by the programmer, until no more equations are applicable. The result
of this process is called a `normal form` which represents the "value" of the
original expression. Keeping with the tradition of term rewriting, there's no
distinction between "defined" and "constructor" function symbols in
Pure. Consequently, any function symbol or operator can be used *anywhere* on
the left-hand side of an equation, and may act as a constructor symbol if it
happens to occur in a normal form term. This enables you to work with
algebraic rules like associativity and distributivity in a direct fashion:
数値や文字列のようないくつかの有名なデータ構造は別として、Pureインタープリタが実際に行うのは、記号代数的なやり方で式を評価し、プログラマーが与えた等式によって式を書き換えてゆき、もうそれ以上は等式を適用できなくなるまで続けることです。この処理の結果は「正規形」と呼ばれ、元々の式の「値」〔"value"〕を表します。項書き換えという流儀を貫くことにより、Pure内では「定義済み」〔"defined"〕関数シンボルと「コンストラクタ」〔"constructor"〕関数シンボルの区別はありません。その結果、あらゆる関数シンボルや演算子は等式左辺の *どこでも* 使うことができ、もし正規形の項の中に現れた場合にはコンストラクタシンボルとして振る舞うことが許されます。このことにより、あなたは結合や分配のような代数のルールをそのままのやり方で使うことができます::
> (x+y)*z = x*z+y*z; x*(y+z) = x*y+x*z;
> x*(y*z) = (x*y)*z; x+(y+z) = (x+y)+z;
> square (a+b);
a*a+a*b+b*a+b*b
Note that, in contrast, languages like Haskell and ML always enforce the
so-called "constructor discipline", which stipulates that only pure
constructor symbols (without any defining equations) may occur as a subterm on
the left-hand side of a definition. Thus equational definitions like the above
are forbidden in these languages. In Pure such definitions are just normal
business, which makes the language directly usable as a tool for symbolic
algebra.
これに対して、 Haskell や ML のような言語がいわゆる「コンストラクタ原則」を常に強制することに注意して下さい。「コンストラクタ原則」の規定では、純粋なコンストラクタシンボル(いかなる定義的な等式も伴わない)だけしか定義左辺内の下位項〔subterm〕として現れることを許されません。したがって、これらの言語では上のような等式定義が許されません。しかしこのような定義は Pure では普通のことです。こうした特徴により、 Pure は記号代数のツールとして直接使えるものになっています。
Parameters in Equations
-----------------------
等式のパラメータ
Taking a look at the above examples, you might have been wondering how the
Pure interpreter figures out what the parameters (a.k.a. "variables") in an
equation are. This is quite obvious in rules involving just variables and
special operator symbols, such as ``(x+y)*z = x*z+y*z``. However, what about
an equation like ``foo (foo bar) = bar``? Since most of the time we don't
declare any symbols in Pure, how does the interpreter know that ``foo`` is a
literal function symbol here, while ``bar`` is a variable?
前段で挙げた例を見て、あなたはPureのインタープリタが等式中の何をパラメータ(「変数」とも呼ばれる)として理解するのか不思議に思っているかもしれません。例えば ``(x+y)*z = x*z+y+z`` のように、単に変数と演算専用の記号だけを含むルールであれば、この区別ははっきりしています。しかし ``foo (foo bar) = bar`` のような等式ではどうでしょうか? Pureを使うほとんどの機会において私たちはいかなる記号も定義しないのに、インタープリタは ``foo`` がここで関数リテラルのシンボルであり、 ``bar`` が変数であることを理解できるのでしょうか?
The answer is that the interpreter considers the different positions in the
left-hand side expression of an equation. Basically, a Pure expression is just
a tree formed by applying expressions to other expressions, with the atomic
subexpressions like numbers and symbols at the leaves of the tree. (This is
even true for infix expressions like ``x+y``, since in Pure these are always
equivalent to a function application of the form ``(+) x y`` which has the
atomic subterms ``(+)``, ``x`` and ``y`` at its leaves.)
答えはこういうことです。インタープリタは等式の左辺にある式の異なる位置を考えます。Pureの式は基本的に、ある式を他の式に適用する単なるツリー形状をとり、そのツリーの枝には、数値や記号などアトム的な下位式〔subexpressions〕が葉として付いています(このことは ``x+y`` のような挿入演算子の式〔infix expressions〕についても当てはまります。なぜならPureにおいてこれらは ``(+) x y`` という形式の関数アプリケーションと常に等価〔equivalent〕であり、この式は ``(+)`` と ``x`` と ``y`` というアトム的な下位項〔subterms〕を葉として持っていることになります)。
Now the interpreter divides the leaves of the expression tree into "head" (or
"function") and "parameter" (or "variable") positions based on which leaves
are leftmost in a function application or not. Thus, in an expression like ``f
x y z``, ``f`` is in the head or function position, while ``x``, ``y`` and
``z`` are in parameter or variable positions. (Note that in an infix
expression like ``x+y``, ``(+)`` is the head symbol, not ``x``, as the
expression is really parsed as ``(+) x y``, see above.)
今やインタープリタは式の木についている複数の葉を「頭」(または「関数」)の位置と「パラメータ」(または「変数」)の位置に分割し、最も左にある葉は関数アプリケーションの位置を占めることになり、他はそうなりません。したがって、 ``f x y z`` のような式のうち、 ``f`` は頭もしくは関数の位置にあり、 ``x`` と ``y`` と ``z`` はパラメータもしくは変数の位置にあることになります(``x+y`` のような挿入演算子の式では、 あくまで ``(+)`` が頭部シンボルであり、決して ``x`` ではないことに注意して下さい。上で説明したように、この式は ``(+) x y`` として構文解析されます)。
■headは「先頭」とすべきだろうか?
Identifiers in head positions are taken as literal function symbols by the
interpreter, while identifiers in variable positions denote, well,
variables. We also refer to this convention as the `head = function rule`. It
is quite intuitive and lets us get away without declaring the variables in
equations. (There are some corner cases not covered here, however. In
particular, Pure allows you to declare special constant symbols, if you need a
symbol to be recognized as a literal even if it occurs in a variable
position. This is done by means of a ``nonfix`` declaration, see `Symbol
Declarations`_ for details.)
頭の位置にある識別子はインタープリタによって関数リテラルのシンボルとして扱われ、それに対して変数の位置にある識別子は、そう、変数を与えます。私たちはこのしきたりを `頭=関数ルール` と呼んで言及しています。このルールはとても直感的で、等式内で変数を宣言することなく私たちは先へ進むことができます(ただし、ここではカバーしきれない厄介なケースも存在します。特に、あなたがある記号を、それが変数の位置に置かれる時でもリテラルとして認識させる必要があるならば、Pureでは特別な定数記号として宣言することが許されています。これは ``nonfix`` 宣言を通じて可能です。詳しくは `Symbol Declarations`_ を参照して下さい)。
Expression Syntax
-----------------
式の構文
The Pure language provides built-in support for machine integers (32 bit),
bigints (implemented using GMP_), floating point values (double precision IEEE
754), character strings (UTF-8 encoded) and generic C pointers (these don't
have a syntactic representation in Pure, though, so they need to be created
with external C functions). Truth values are encoded as machine integers (as
you might expect, zero denotes *false* and any non-zero value *true*). Pure
also provides some built-in support for lists and matrices, although most of
the corresponding operations are actually defined in the prelude.
Pure言語は以下のデータ型を組み込みサポートしています。machine integer (32 bit), bigint ( GMP_ を使って実装)、浮動小数点値(IEEE 754 倍精度)、character strings (UTF-8 encoded) 、ジェネリック C ポインタ(ただし、ポインタは syntactic representation を持たず、そのため外部C関数として作られる必要がある)。真偽値はmachine integerにエンコードされます(おそらくあなたの想像通り、ゼロは *false* を表し、あらゆる非ゼロ値は *true* を表します)。Pureはまた、リストとマトリクスの組み込みサポートを提供しており、それらに対応する演算〔operation〕は実際には prelude 内で定義されています。
Expressions consist of the following elements:
式は以下の要素から構成されます:
Numbers: ``4711``, ``4711L``, ``1.2e-3``
The usual C notations for integers (decimal: ``1000``, hexadecimal:
``0x3e8``, octal: ``01750``) and floating point values are all provided.
Integers can also be denoted in base 2 by using the ``0b`` or ``0B``
prefix: ``0b1111101000``. Integer constants that are too large to fit into
machine integers are promoted to bigints automatically. Moreover, integer
literals immediately followed by the uppercase letter ``L`` are always
interpreted as bigint constants, even if they fit into machine integers.
This notation is also used when printing bigint constants, to distinguish
them from machine integers.
数値: ``4711``, ``4711L``, ``1.2e-3``
従来のCの記数法で、整数(10進数: ``1000`` 、16進数: ``0x3e8`` 、8進数: ``01750``)と浮動小数点数がすべてサポートされます。整数はまた ``0b`` か ``0B`` プレフィクスを使って2進数でも記述できます: ``0b1111101000`` 。machine integerでは大きすぎて表現しきれない整数の定数は自動的に bigint へ昇格されます。さらに言えば、整数リテラルの直後に大文字の ``L`` が付いている場合、たとえ machine integer で表現しうるものでも常に bigint 定数として解釈されます。 machine integer との区別を明確にするため、この記数法は bigint 定数を出力するときでも貫かれます。
Strings: ``"Hello, world!\n"``
String constants are double-quoted and terminated with a null character,
like in C. In difference to C, strings are always encoded in UTF-8, and
character escapes in Pure strings have a more flexible syntax (borrowed
from the author's Q language) which provides notations to specify any
Unicode character. In particular, the notation ``\``\ *n*, where *n* is an
integer literal written in decimal (no prefix), hexadecimal (``0x``
prefix), octal (``0`` prefix) or binary (``0b`` prefix) notation, denotes
the Unicode character (code point) #\ *n*. Since these escapes may consist
of a varying number of digits, parentheses may be used for disambiguation
purposes; thus, e.g. ``"\(123)4"`` denotes character #123 followed by the
ASCII character ``4``. The usual C-like escapes for special non-printable
characters such as ``\n`` are also supported. Moreover, you can use
symbolic character escapes of the form ``\&``\ *name*\ ``;``, where *name*
is any of the XML single character entity names specified in the `XML
Entity definitions for Characters`__. Thus, e.g., ``"\&copy;"`` denotes
the copyright character (code point 0x000A9).
__ http://www.w3.org/TR/xml-entity-names/
文字列: ``"Hello, world!\n"``
文字列定数は C と同じように、ダブルクォートで囲まれヌル文字で終わります。 C と異なるのは、文字列が常に UTF-8 でエンコードされること、また Pure の文字エスケープが C よりも柔軟な構文規則〔syntax〕を持っていることです(同じ作者の Q 言語から借りてきています)。この構文規則はあらゆる Unicode 文字を特定する記法を提供します。特に ``\``[ *n* という表記法( *n* は10進法(プレフィクスなし)、16進数( ``0x`` プレフィクス)、8進数( ``0`` プレフィクス、2進数( ``0b`` プレフィクス)いずれかの整数リテラルで示す)は、 Unicode 文字(コードポイント) #\ *n* を示します。このエスケープは様々な数字で構成することができるので、括弧を使って曖昧さを排除することができます。例えば ``"\(123)4"`` は #123 の後にASCII文字の ``4`` が続いていることを示します。従来の C 方式に似た ``\n`` のような非表示の特殊文字エスケープもサポートされます。さらには ``\&``\ *name*\ ``;`` 形式の記号文字エスケープ( *name* は `XML Entity definitions for Characters`__ で定義される単一文字エンティティ名)も使えます。したがって、例えば ``"&copy;"`` はコピーライト文字(コードポイント 0x000A9)を表します。
__ http://www.w3.org/TR/xml-entity-names/
Function and variable symbols: ``foo``, ``foo_bar``, ``BAR``, ``foo::bar``
These consist of the usual sequence of letters (including the underscore)
and digits, starting with a letter. Case is significant, thus ``foo``,
``Foo`` and ``FOO`` are distinct identifiers. The '``_``' symbol, when
occurring on the left-hand side of an equation, is special; it denotes the
`anonymous variable` which matches any value without actually binding a
variable. Identifiers can also be prefixed with a namespace identifier,
like in ``foo::bar``. (This requires that the given namespace has already
been created, as explained under Namespaces_ in the Declarations_ section.)
関数シンボルと変数シンボル: ``foo``, ``foo_bar``, ``BAR``, ``foo::bar``
関数と変数を表すシンボルはひとつながりの文字(アンダーバーを含む)と数字で構成され、必ず文字から始まります。大文字と小文字は区別されるので ``foo`` と ``Foo`` と ``FOO`` は別個の識別子です。 ``_`` 記号は、等式の左辺に現れたとき、特別なものとなります。このとき ``_`` は `匿名変数` を示し、実際に変数と束縛されることなくいかなる値にもマッチします。また ``foo::bar`` のように関数・変数の識別子の前に名前空間の識別子を付けることも可能です(この場合、付加した名前空間がすでに作成されていることが必要です。 Declarations_ セクション内 Namespaces_ 部で説明している通りです)。
Operator and constant symbols: ``x+y``, ``x==y``, ``not x``
For convenience, Pure also provides you with a limited means to extend the
syntax of the language with special operator and constant symbols by means
of a corresponding `fixity` declaration, as discussed in section
`Symbol Declarations`_. Besides the usual infix, prefix and postfix
operators, Pure also provides outfix (bracket) and nonfix (constant)
symbols. (Nonfix symbols actually work more or less like ordinary
identifiers, but the ``nonfix`` attribute tells the compiler that when
such a symbol occurs on the left-hand side of an equation, it is always to
be interpreted as a literal constant, cf. `Parameters in Equations`_.)
演算子シンボルと定数シンボル: ``x+y``, ``x==y``, ``not x``
Pure では便宜のために、言語の構文規則を、特別な演算子シンボルと定数シンボルによって拡張する手段をいくつか提供しています。これは、それぞれ用意されている `fixity` 宣言を使って行います( `Symbol Declarations`_ セクションで議論されています)。従来の挿入〔infix〕、前置〔prefix〕、後置〔postfix〕演算子に加え、 Pure はアウトフィクス(括弧)とノンフィクス(定数)シンボルも提供します(ノンフィクスシンボルは、実際には多かれ少なかれ普通の識別子と同じような働きをしますが、 ``nonfix`` 属性はコンパイラに対して以下のように伝える点が異なります。そのようなシンボルが等式の左辺に現れたとき、そのシンボルを常にリテラル定数と扱え、と伝えるのです。 cf. `Parameters in Equations`_ )
Operator and constant symbols may take the form of an identifier or a
sequence of punctuation characters. They must always be declared before
use. Once declared, they are always special, and can't be used as ordinary
identifiers any more. However, like in Haskell, by enclosing an operator
in parentheses, such as ``(+)`` or ``(not)``, you can turn it into an
ordinary function symbol. Also, operators and constant symbols can be
qualified with a namespace just like normal identifiers.
演算子シンボルと定数シンボルは、1つの識別子か、句読点文字のシーケンスという形をとることができます。それらは常に使用前に宣言される必要があります。一度宣言されたら、それらシンボルは常に特別であり、もはや通常の識別子として使うことはできません。しかし、 Haskell と同じように、 ``(+)`` や ``(not)`` のように演算子を丸括弧で囲うことにより通常の関数シンボルへ変えることができます。また、演算子シンボルと定数シンボルを、普通の識別子とまったく同じように名前空間で修飾することも可能です。
Lists: ``[x,y,z]``, ``x:xs``, ``x..y``, ``x:y..z``
Pure's basic list syntax is the same as in Haskell, thus ``[]`` is the
empty list and ``x:xs`` denotes a list with head element ``x`` and tail
list ``xs``. (The infix constructor symbol '``:``' is declared in the
prelude.) The usual syntactic sugar for list values in brackets is
provided, thus ``[x,y,z]`` is exactly the same as ``x:y:z:[]``.
リスト: ``[x,y,z]``, ``x:xs``, ``x..y``, ``x:y..z``
Pure の基本的なリスト文法は Haskell と同じです。なので ``[]`` は空リストを、 ``x:xs`` は ``x`` が先頭要素で後の残りが ``xs`` であるリストを示します(挿入コンストラクタシンボル '``:``' は prelude で宣言されています)。角括弧はリスト値を表すよくある糖衣構文として提供されるので、 ``[x,y,z]`` は ``x:y:z:[]`` とまったく同じことです。
There's also a way to denote arithmetic sequences such as ``1..5``, which
denotes the list ``[1,2,3,4,5]``. (Haskell users should note the missing
brackets. In difference to Haskell, Pure doesn't use any special syntax
for arithmetic sequences, the '``..``' symbol is just an ordinary infix
operator declared and defined in the prelude.) Sequences with arbitrary
stepsizes can be written by denoting the first two sequence elements using
the '``:``' operator, as in ``1.0:1.2..3.0``. (To prevent unwanted
artifacts due to rounding errors, the upper bound in a floating point
sequence is always rounded to the nearest grid point. Thus, e.g.,
``0.0:0.1..0.29`` actually yields ``[0.0,0.1,0.2,0.3]``, as does
``0.0:0.1..0.31``.)
``1..5`` のような形で等差数列を示す方法もあります。この例は ``[1,2,3,4,5]`` を表します( Haskell ユーザは角括弧(ブラケット)が無いことに注意して下さい。 Haskell とは異なり、 Pure は数列のために特別な文法は使いません。 '``..``' 記号は単なる普通の挿入演算子で、 prelude 内で宣言と定義が行われています)。任意の差〔stepsizes〕は数列の最初の2要素に '``:``' を使って、 ``1.0:1.2..3.0`` のように表すことができます(四捨五入のエラーのせいで作為的な数値が混入するのを防ぐため、浮動小数点数列の境界上位は常に最も近いグリッドポイントに丸められます。例えば ``0.0:0.1..0.29`` は実際には ``[0.0,0.1,0.2,0.3]`` をもたらし、また ``0.0:0.1..0.31`` も同じ結果となります。
■TODO 小数点以下の揃えられ方について訳註として詳説を加えたい。
Tuples: ``x,y,z``
Pure's tuples are a bit unusual: They are constructed by just "pairing"
things using the '``,``' operator, for which the empty tuple ``()`` acts
as a neutral element (i.e., ``(),x`` is just ``x``, as is ``x,()``). Pairs
always associate to the right, meaning that ``x,y,z == x,(y,z) ==
(x,y),z``, where ``x,(y,z)`` is the normalized representation. This
implies that tuples are always flat, i.e., there are no nested tuples
(tuples of tuples); if you need such constructs then you should use lists
instead. Also note that parentheses are generally only used to group
expressions and are *not* part of the tuple syntax in Pure, *except* if
you need to include a tuple in a list or matrix. E.g., ``[(1,2),3,(4,5)]``
is a three element list consisting of the tuple ``1,2``, the integer
``3``, and another tuple ``4,5``. Likewise, ``[(1,2,3)]`` is a list with a
single element, the tuple ``1,2,3``.
タプル: ``x,y,z``
Pure のタプルは少し珍しいものです: タプルは '``,``' を使って単純に「ペアになった」何かです。そのため、空のタプル ``()`` はニュートラルな要素として振る舞います(つまり ``(),x`` は単に ``x`` であり、 ``x,()`` もまた同様です)。ペアは常に右側のものと結びつきます。つまり ``x,y,z == x,(y,z) == (x,y),z`` であり、ここでは ``x,(y,z)`` が正規化された表現となります。このことは、タプルが常にフラットであることを含意しています。すなわち、ネストされたタプル(タプルのタプル)というものはありません。もし入れ子の構造が必要なら、タプルの代わりにリストを使うべきです。また、丸括弧は通例では式をグループ化するためだけに使われるもので、 Pure のタプル文法の一部では *ない* ことに注意して下さい。 *ただし* マトリクスやリスト内にタプルを含める必要がある場合は別です。例えば ``[(1,2),3,(4,5)]`` は 1,2 のタプル、整数 3 、もう一つのタプル ``4,5`` という3つの要素からなるリストです。同様に ``[(1,2,3)] は ``1,2,3`` という1つのタプルを持つリストです。
Matrices: ``{1.0,2.0,3.0}``, ``{1,2;3,4}``, ``{1L,y+1;foo,bar}``
Pure also offers matrices, a kind of arrays, as a built-in data structure
which provides efficient storage and element access. These work more or
less like their Octave/MATLAB equivalents, but using curly braces instead
of brackets. As indicated, commas are used to separate the columns of a
matrix, semicolons for its rows. In fact, the ``{...}`` construct is
rather general, allowing you to construct new matrices from individual
elements and/or submatrices, provided that all dimensions match up. E.g.,
``{{1;3},{2;4}}`` is another way to write a 2x2 matrix in "column-major"
form (however, internally all matrices are stored in C's row-major
format).
マトリクス: ``{1.0,2.0,3.0}``, ``{1,2;3,4}``, ``{1L,y+1;foo,bar}``
Pure はマトリクスも提供します。マトリクスは配列の一つで、組み込みのデータ構造であり、効率のよい保存とアクセスを提供します。これらは Ooctave/MATLAB のそれとだいたい同じように動作しますが、角括弧(ブラケット)の代わりに波括弧を使います。すでに示されているように、カンマはマトリクスの列〔columns〕を分け、セミコロンは行〔rows〕を分けます。実際、 ``{...}`` 構造はgeneralであり、すべての次元が一致していれば、個別の要素 and/or サブマトリクスから新しいマトリクスを作ることを許します。例えば ``{{1;3},{2;4}}`` は 2x2 のマトリクスをさきほどと別の「列優先」〔"column-major"〕フォーマットで書く方法です(とはいえ、内部的にはすべてのマトリクスはCの行優先フォーマットで保存されます)。
Note that, while the ``[...]`` and ``{...}`` constructs look superficially
similar, they work in very different ways. The former is just syntactic
sugar for a corresponding constructor term and can thus be used as a
pattern on the left-hand side of an equation. In contrast, the latter is a
built-in operation which creates objects of a special matrix type. These
can *not* be used as patterns (instead, matrix values can be matched using
the special ``matrix`` type tag, see the `Rule Syntax`_ section for
details).
``[...]`` と ``{...}`` は構造の外見がよく似ているのに対して、動作はそれぞれ非常に異なることに注意して下さい。前者は単に、対応するコンストラクタの syntactic sugar であり、そのため等式左辺のパターンとして使用できます。それと対照的に、後者は組み込み処理の一つであり、専用のマトリクス型を持つオブジェクトを生み出します。こちらはパターンとして使うことはでき *ません* (その代わり、マトリクスの値は専用の ``matrix`` 型タグを使ってマッチさせることができます。詳しくは `Rule Syntax`_ セクションを参照して下さい)。
Pure supports both numeric and symbolic matrices. The former are
homogeneous arrays of double, complex double or (machine) int matrices,
while the latter can contain any mixture of Pure expressions. Pure will
pick the appropriate type for the data at hand. If a matrix contains
values of different types, or Pure values which cannot be stored in a
numeric matrix, then a symbolic matrix is created instead (this also
includes the case of bigints, which are considered as symbolic values as
far as matrix construction is concerned). Numeric matrices use an internal
data layout that is fully compatible with the `GNU Scientific Library`_
(GSL), and can readily be passed to GSL routines via the C interface. (The
Pure interpreter does not require GSL, however, so numeric matrices will
work even if GSL is not installed.)
Pure は数値マトリクスと記号マトリクスの両者をサポートします。前者は double, complex double or (machine) int の均質な配列〔homogeneous arrays〕であり、対する後者は Pure のいかなる式をも内包することができます。 Pure は各データのために適切な型を採用するでしょう。もしマトリクスがそれぞれ型の異なる値を含んでいたら、あるいは数値マトリクスに保存できない Pure の値を含んでいたら、その代わりに代数マトリクスが創り出されます(これには bigint の場合も含まれます。マトリクス構造に関する限り bigint は代数値とみなされます)。数値マトリクスは `GNU Scientific Library` (GSL) と完全互換のデータレイアウトを使っており、Cインターフェースを使ってGSLへ容易に渡すことが可能です(しかし Pure インタープリタは GSL を必要としないので、数値マトリクスは GSL がインストールされていなくても動作します)。
More information about matrices and corresponding examples can be found in
the Examples_ section below.
マトリクスに関する詳細やそれぞれの例は Example_ セクションにあります。
Comprehensions: ``[x,y | x=1..n; y=1..m; x<y]``, ``{f x | x=1..n}``
Pure provides both list and matrix comprehensions as a convenient means to
construct list and matrix values from a "template" expression and one or
more "generator" and "filter" clauses. The former bind a pattern to values
drawn from a list or matrix, the latter are just predicates determining
which generated elements should actually be added to the result. Both list
and matrix comprehensions are in fact syntactic sugar for a combination of
nested lambdas, conditional expressions and "catmaps" (a collection of
operations which combine list or matrix construction and mapping a
function over a list or matrix, defined in the prelude), but they are
often much easier to write.
内包: ``[x,y | x=1..n; y=1..m; x<y]``, ``{f x | x=1..n}``
Pure はリストとマトリクスの内包を提供します。これはリスト値やマトリクス値を、 "template" 式や、1つ以上の "generator" や "filter" 節から構成するのに便利なものです。前者は、あるパターンを、リストかマトリクスで描写される値にバインドします。後者は、生成される要素のどれを結果に追加するか定義しているだけです。リスト内包とマトリクス内包の両者は、実際には、ネストされたラムダと、条件式と、 "catmaps" (リスト構造やマトリクス構造を結合し、ある関数をリストやマトリクスにマッピングする処理のコレクションで、 prelude 内で定義される)を組み合わせた糖衣構文です。しかし■それら■のほうがしばしば簡単に書けます。
Matrix comprehensions work pretty much like list comprehensions, but
produce matrices instead of lists. List generators in matrix
comprehensions alternate between row and column generation so that most
common mathematical abbreviations carry over quite easily. Examples of
both kinds of comprehensions can be found in the Examples_ section below.
マトリクス内包はリスト内包とほとんど同じように動作しますが、リストの代わりにマトリクスを作り出します。マトリクス内包のリストジェネレータは、行と列の生成を異なるものにします。そのため、数学的な abbreviations のほとんどをとても簡単に持ち越すことができます。両種の内包の例は下部 Examples_ セクションにあります。
Function and operator applications: ``foo x y z``, ``-x``, ``x+y``, ``(+x)``
As in other modern FPLs, function applications are written simply as
juxtaposition (i.e., in "curried" form) and associate to the left. This
means that in fact all functions only take a single argument.
Multi-argument functions are represented as chains of single-argument
functions. For instance, in ``f x y = (f x) y`` first the function ``f``
is applied to the first argument ``x``, yielding the function ``f x``
which in turn gets applied to the second argument ``y``. This makes it
possible to derive new functions from existing ones using `partial
applications` which only specify some but not all arguments of a
function. For instance, taking the ``max`` function from the prelude as an
example, ``max 0`` is the function which, for a given ``x``, returns ``x``
itself if it is nonnegative and zero otherwise. This works because
``(max 0) x = max 0 x`` is the maximum of ``0`` and ``x``.
関数と演算子の適用: ``foo x y z``, ``-x``, ``x+y``, ``(+x)``
他の現代的な関数型言語と同じく、関数適用はシンプルに並置して(つまり「カリー化された」形式)書き、左と結合します。つまり、実際にはすべての関数は引数を1つだけ取ることを意味します。複数の引数を取る関数は、引数1つの関数をつなげたものとして表現されます。例えば ``f x y = (f x) y`` という例だと、まず ``f`` が最初の引数 ``x`` に適用され、関数 ``f x`` を生み出します。今度はその新たな関数が第2引数 ``y`` に適用されるわけです。このことにより、既存の関数に `部分適用` を行ってそこから新たな関数を導くことが可能となります。 `部分適用` はいくらかの、全部ではない引数を定義します。 例として prelude から ``max`` 関数を取り上げます。 ``max 0`` に ``x`` が与えられたとき、 ``x`` が負であれば ``x`` そのものを、そうでなければゼロを返します。これが機能するのは ``(max 0) x = max 0 x`` が ``0`` と ``x`` の最大値であるからです。
Operator applications are written using prefix, postfix, outfix or infix
notation, as the declaration of the operator demands, but are just
ordinary function applications in disguise. As already mentioned,
enclosing an operator in parentheses turns it into an ordinary function
symbol, thus ``x+y`` is exactly the same as ``(+) x y``. For convenience,
partial applications of infix operators can also be written using
so-called `operator sections`. A *left section* takes the form ``(x+)``
which is equivalent to the partial application ``(+) x``. A *right
section* takes the form ``(+x)`` and is equivalent to the term ``flip (+)
x``. (This uses the ``flip`` combinator from the prelude which is defined
as ``flip f x y = f y x``.) Thus ``(x+) y`` is equivalent to ``x+y``,
while ``(+x) y`` reduces to ``y+x``. For instance, ``(1/)`` denotes the
reciprocal and ``(+1)`` the successor function. (Note that, in contrast,
``(-x)`` always denotes an application of unary minus; the section
``(+-x)`` can be used to indicate a function which subtracts ``x`` from
its argument.)
演算子の適用は、その演算子の宣言にもとづき、前置、後置、アウトフィクス、挿入いずれかの記法を使って書きますが、通常の関数適用が変装しただけのものです。すでに述べたように、ある演算子を丸括弧で囲むと、その演算子は普通の関数シンボルとなります。つまり ``x+y`` は ``(+) x y`` とまったく同じだということです。便宜のため、挿入演算子の部分適用はいわゆる `演算子セクション` を使って書くことも可能です。 *左セクション* は ``(x+)`` という形をとりますが、これは ``(+) x`` の部分適用と等価です。 *右セクション* は ``(+x)`` という形をとり、 ``flip (+) x`` と等価で(prelude から連結子 ``flip`` を使っていますが、これは ``flip f x y = f y x`` と定義されています)、したがって ``(x+) y`` は ``x+y`` と等価であり、それに対して ``(+x) y`` は ``y+x`` へと還元されます。例えば ``(1/)`` は逆数を示し、 ``(+1)`` は後者関数を示します(対照的に、 ``(-x)`` はいつでも単項の負数を示すことに注意して下さい。引数から ``x`` を引く関数を表すには ``(+-x)`` を使うことができます)。
Conditional expressions: ``if x then y else z``
Evaluates to ``y`` or ``z`` depending on whether ``x`` is "true" (i.e., a
nonzero integer). An exception is raised if the condition is not an
integer.
条件式: ``if x then y else z``
``y`` と ``z`` のどちらを評価するかは ``x`` が "true" (つまり非ゼロ数)かどうかに依存します。条件式が整数でない場合は例外が起きます。
Lambdas: ``\x -> y``
These denote anonymous functions and work pretty much like in Haskell.
Pure supports multiple-argument lambdas (e.g, ``\x y -> x*y``), as well as
pattern-matching lambda abstractions which match one or more patterns
against the lambda arguments, such as ``\(x,y) -> x*y``. An exception is
raised if the actual lambda arguments do not match the given patterns.
ラムダ: ``\x -> y``
これらは無名関数を表しており、 Haskell とまったく同じように動作します。 Pure は複数の引数を取るラムダ(例えば ``\x y -> x*y`` )やパターンマッチを行うラムダ抽象〔ラムダ抽出/lambda abstractions〕をサポートします。ラムダ抽出は、ラムダの引数に対して1つ以上のパターンマッチを、例えば ``\(x,y) -> x*y`` のようなかたちで行います。与えられたパターンにラムダの実際の引数がマッチしない場合、例外が起きます。
Case expressions: ``case x of rule; ... end``
Matches an expression, discriminating over a number of different cases,
similar to the Haskell case construct. The expression ``x`` is matched in
turn against each left-hand side pattern in the rule list, and the first
pattern which matches ``x`` gives the value of the entire expression, by
evaluating the corresponding right-hand side with the variables in the
pattern bound to their corresponding values. An exception is raised if the
target expression doesn't match any of the patterns.
Case 式: ``case x of rule; ... end``
Haskell の case 構造と同じく、式のマッチを行い、たくさんのそれぞれ異なる場合を識別します。式 ``x`` はルールリスト中の各左辺のパターンに対して次々マッチを試され、最初に ``x`` にマッチしたパターンが式全体の値を与えます, by evaluating the corresponding right-hand side with the variables in the pattern bound to their corresponding values. ターゲットの式がどのパターンにもマッチしなかった場合は例外が起きます。
When expressions: ``x when rule; ... end``
An alternative way to bind local variables by matching a collection of
subject terms against corresponding patterns, similar to Aardappel_'s
``when`` construct. A single binding such as ``x when u = v end`` is
equivalent to ``case v of u = x end``, but the former is often more
convenient to write. A ``when`` clause may contain multiple definitions,
which are processed from left to right, so that later definitions may
refer to the variables in earlier ones. This is exactly the same as
several nested single definitions, with the first binding being the
"outermost" one.
When 式: ``x when rule; ... end``
ローカル変数を束縛するもう一つの方法です。subject項のコレクションを対応するパターンに対してマッチさせてローカル変数を束縛します。 Aardappel_ の ``when`` 構造と同じです。 ``x when u = v end`` のような単一の束縛は ``case v of u = x end`` と等価ですが、前者のほうが書きやすいことが多いでしょう。 ``when`` 節は複数の定義を含むことができ、この複数の定義は左から右へ処理されます。したがって後にある定義はそれより前にある変数を参照することができます。■これは、単独の定義をいくつかネストした場合とまったく同じで、最初に束縛されたものが "outmost" なものとなります。■
With expressions: ``x with rule; ... end``
Defines local functions. Like Haskell's ``where`` construct, but it can be
used anywhere inside an expression (just like Aardappel's ``where``, but
Pure uses the keyword ``with`` which better lines up with ``case`` and
``when``). Several functions can be defined in a single ``with`` clause,
and the definitions can be mutually recursive and consist of as many
equations as you want.
With 式: ``x with rule; ... end``
ローカル関数を定義します。 Haskell の ``where`` 構造と似ていますが、 ``with`` は式の中のどこででも使うことができます(ちょうど Aardappel の ``where`` と同じようなものですが、 Pure は ``with`` キーワードを使います which better lines up with ``case`` and ``when``)。 ``with`` 節の内側で複数の関数を定義することでき、またそれらの関数が相互に再帰的であることもできますし、あなたが望むだけたくさんの等式で構成することもできます。
Operators and Precedence
------------------------
演算子と優先順位
Expressions are parsed according to the following precedence rules: Lambda
binds most weakly, followed by ``when``, ``with`` and ``case``, followed by
conditional expressions (``if``-``then``-``else``), followed by the `simple
expressions`, i.e., all other kinds of expressions involving operators,
function applications, constants, symbols and other primary
expressions. Precedence and associativity of operator symbols are given by
their declarations (cf. `Symbol Declarations`_), and function application
binds stronger than all operators. Parentheses can be used to override default
precedences and associativities as usual.
式は以下の優先順位に従って構文解析されます: ラムダは最も弱く結びつきます。 ``when``, ``with`` and ``case`` が後続する、条件式( ``if``-``then``-``else`` )が後続する、`シンプルな式`、つまり他のあらゆる種類の式(演算子、関数アプリケーション、定数、シンボルと other primary expressions を含む)が後続する。演算子シンボルの優先度と結合しやすさは、その宣言により与えられます(cf. `Symbol Declarations`_ )。また関数アプリケーションは全演算子よりも強く結びつきます。例によって、丸括弧を使うとデフォルトの優先度と結合しやすさをオーバーライドできます。
The common operator symbols like ``+``, ``-``, ``*``, ``/`` etc. are all
declared at the beginning of the prelude, see the `Pure Library Manual`_ for a
list of these. Arithmetic and relational operators mostly follow C
conventions. However, out of necessity (``!``, ``&`` and ``|`` are used for
other purposes in Pure) the logical and bitwise operations, as well as the
negated equality predicates are named a bit differently: ``~``, ``&&`` and
``||`` denote logical negation, conjunction and disjunction, while the
corresponding bitwise operations are named ``not``, ``and`` and
``or``. Moreover, following these conventions, inequality is denoted
``~=``. Also note that ``&&`` and ``||`` are special forms which are evaluated
in short-circuit mode (see below), whereas the bitwise connectives receive
their arguments using call-by-value, just like the other arithmetic
operations.
``+``, ``-``, ``*``, ``/`` などなどありふれた演算子シンボルはすべて prelude の先頭で宣言されています。これらのリストは `Pure Library Manual`_ で参照できます。算術演算子および関係演算子はほとんどCの慣例を踏襲しています。しかし、やむを得ず(Pure では ``!`` と ``&`` と ``|`` を他の目的に使っていますが)論理演算、ビット演算、negated equality predicates はちょっと違う記号を使っています: ``~``, ``&&`` and ``||`` はそれぞれ論理否定、連言命題、選言命題を表します。他方、それぞれに対応するビット演算子は ``not`` ``and`` ``or`` を使います。さらに、これらの慣習を踏襲して、等しくないこと〔inequality〕は ``~=`` で示します。また ``&&`` と ``||`` が特別形であり短絡モード(下部参照)で評価されること、その一方で、ビット結合子が他の算術演算子と同じように call-by-name を用いて引数を受けとることを覚えておいて下さい。
Special Forms
-------------
特別形
As already mentioned, some operations are actually implemented as special
forms. In particular, the conditional expression ``if x then y else z`` is a
special form with call-by-name arguments ``y`` and ``z``; only one of the
branches is actually evaluated, depending on the value of ``x``. Similarly,
the logical connectives ``&&`` and ``||`` evaluate their operands in
short-circuit mode. Thus, e.g., ``x&&y`` immediately becomes false if ``x``
evaluates to false, without ever evaluating ``y``. The built-in definitions of
these operations work as if they were defined by the following equations (but
note that the second operand is indeed passed "by name", so that it isn't
evaluated unless its value is actually needed):
すでに述べた通り、いくつかの演算は実際には特別形として実装されています。特に、条件式 ``if x then y else z`` は名前呼出しの引数 ``y`` と ``z`` を伴う特別形です。 ``x`` の値によって、枝の片方だけが実際に評価されます。同じように、論理結合子 ``&&`` と ``||`` はオペランドを短絡モードで評価します。したがって、例えば ``x&&y`` は ``x`` が偽と評価されるとただちに偽となり、 ``y`` が評価されることはありません。この処理の組み込み定義は、あたかも次のように定義された等式のように動作します(しかし2番目のオペランドは実のところ "by name" で渡されることを覚えておいて下さい。その結果として、2番目のオペランドの値は実際に必要とされない限り評価されないわけです)::
x::int && y = if x then x else y;
x::int || y = if x then y else x;
(Note that this isn't quite the same as in C, as the results of these
operations are *not* normalized, i.e., they may return nonzero values other
than 1 to denote "true". This has the advantage that ``&&`` and ``||`` can be
implemented tail-recursively, see `Stack Size and Tail Recursion`_. Thus, if
you need a normalized truth value then you'll have to make sure that either
both operands are already normalized, or you'll have to normalize the result
yourself.)
(これはCの場合とまったく同じというわけではありません。というのもこれらの処理の結果は正規化され *ない* からです。すなわち、これらの処理は "true" を示すために1意外の非ゼロ値を返す可能性があります。このことには ``&&`` と ``||`` を末尾再帰で実装できるという利点があります(`Stack Size and Tail Recursion`_ を参照して下さい)。したがって、もし正規化された真偽値を必要とする場合、あなたは両方のオペランドいずれもがすでに正規化されていることを確認するか、あるいは結果そのものをあなたが自分で正規化しなければなりません。
If the built-in definitions of ``&&`` and ``||`` fail then both operands are
evaluated and the resulting symbolic term is reduced using the equations
specified by the programmer, which allows you to extend the definitions of
``&&`` and ``||`` just as with other builtins. Also note that if the result
term is in normal form then it is returned as is, thus ``&&`` and ``||`` can
be used in symbolic evaluations as usual. For instance, the following
equations let you compute the disjunctive normal form of logical expressions:
``&&`` と ``||`` の組み込み定義が fail した場合、両方のオペランドが評価され、プログラマーにより定義された等式を使って the resulting symbolic term is reduced. このことにより、あなたは ``&&`` と ``||`` の定義を、他の組み込み演算子と同じように拡張することができます。また、結果の項が正規形である場合、そのまま返されます。したがって ``&&`` と ``||`` を普通通り記号代数評価に使うことができます。例えば、次の等式を使うと論理式の選言的な正規形を計算することができます。::
// eliminate double negations:
// 二重否定を排除する:
~~a = a;
// de Morgan's laws:
// ド・モルガンの法則:
~(a || b) = ~a && ~b;
~(a && b) = ~a || ~b;
// distributivity:
// 分配法則
a && (b || c) = a && b || a && c;
(a || b) && c = a && c || b && c;
// associativity:
// 結合法則
(a && b) && c = a && (b && c);
(a || b) || c = a || (b || c);
Example:
例::
> a || ~(b || (c && ~d));
a||~b&&~c||~b&&d
The sequencing operator ``$$`` evaluates its left operand, immediately throws
the result away and then goes on to evaluate the right operand which gives the
result of the entire expression. This operator is useful to write
imperative-style code such as the following prompt-input interaction:
連続演算子〔sequencing operator〕 ``$$`` は左オペランドを評価し、ただちに結果を出し、続けて右オペランドを評価し、それが式全体の結果となります。この演算子は、プロンプト入力のような、命令的なコードを書くのに便利です。::
> using system;
> puts "Enter a number:" $$ scanf "%g";
Enter a number:
21
21.0
We mention in passing here that the same effect can be achieved with a
``when`` clause, which also allows you to execute a function solely for its
side-effects and just ignore the return value:
ついでに言っておくと ``when`` 節も同じ目的に使えます。 ``when`` 節は副作用〔side-effects〕を得るために関数を単独で実行することを許し、返値をただ無視します::
> scanf "%g" when puts "Enter a number:" end;
Enter a number:
21
21.0
The ``&`` operator does lazy evaluation. This is the only postfix operator
defined in the standard prelude, written as ``x&``, where ``x`` is an
arbitrary Pure expression. It turns its operand into a kind of parameterless
anonymous closure, deferring its evaluation. These kinds of objects are also
commonly known as `thunks` or `futures`. When the value of a future is
actually needed (during pattern-matching, or when the value becomes an
argument of a C call), it is evaluated automatically and gets memoized, i.e.,
the computed result replaces the thunk so that it only has to be computed
once. Futures are useful to implement all kinds of lazy data structures in
Pure, in particular: lazy lists a.k.a. streams. A `stream` is simply a list
with a thunked tail, which allows it to be infinite. The Pure prelude defines
many functions for creating and manipulating these kinds of objects; further
details and examples can be found in the Examples_ section below.
``&`` 演算子は遅延評価を行います。標準preludeで唯一定義されている後置演算子で、 ``x`` が Pure の任意の式であるとき ``x&`` と書きます。この演算子はオペランドを一種の無名クロージャへと変え、評価を延期します。この種のオブジェクトは `thunk` や `future` としても知られています。 future の値は実際に必要とされたとき(パターンマッチングの間や、値がC呼び出しの引数となったとき)、自動的に評価され記憶されます。つまり、計算された結果がサンク〔thunk〕と入れ替わるので、サンクは一度だけ計算される必要が生じます。 future は Pure においてあらゆる種類の遅延評価データ構造を実装するのに役立ちます。特に遅延リスト a.k.a. ストリームを実装するために。`stream` は thunked tail を持つ単なるリストで、無限大になることもできます。 Pure の prelude は、この種のオブジェクトを創り、操作するための関数をたくさん定義します。さらなる詳細と具体例は下部 Examples_ セクションにあります。
Last but not least, the special form ``quote`` quotes an expression, i.e.,
``quote x`` (or, equivalently, ``'x``) returns just ``x`` itself without
evaluating it. The prelude also provides a function ``eval`` which can be used
to evaluate a quoted expression at a later time. For instance:
最後になってしまいましたが、 ``quote`` 形式はある式をクォートします。すなわち ``quote x`` (あるいは ``'x`` でも等価)は単に ``x`` を返し、評価は行いません。 prelude はまた ``eval`` 関数を提供します。 ``eval`` はクォートされた式を後で評価することができます。例えば::
> let x = '(2*42+2^12); x;
2*42+2^12
> eval x;
4180.0
The quote also inhibits evaluation inside matrix values, including the
"splicing" of embedded submatrices:
クォートはマトリクス内の値を評価することも抑制します。これには埋め込まれたサブマトリクスの接合〔"splicing"〕を抑制することも含まれます::
> '{1,2+3,2*3};
{1,2+3,2*3}
> '{1,{2,3},4};
{1,{2,3},4}
The ``quote`` should be well familiar to Lisp programmers. However, there are
some notable differences, please see `The Quote`_ in the `Caveats and Notes`_
section for details and more examples.
``quote`` は Lisp プログラマーには非常に親しみのあるものでしょう。しかし、注意すべき違いがいくつかあります。さらなる詳細と例は `Caveats and Notes`_ セクション内 `The Quote`_ を参照して下さい。
Toplevel
--------
トップレベル
At the toplevel, a Pure program basically consists of rewriting rules (which
are used to define functions and macros), constant and variable definitions,
and expressions to be evaluated:
トップレベル〔最上位層〕では、 Pure プログラムは基本的に書き換えルール(関数やマクロを定義するのに使われる)、定数と変数の定義、評価されるべき式で構成されます。
Rules: ``lhs = rhs;``
Rewriting rules always combine a left-hand side pattern (which must be a
simple expression) and a right-hand side (which can be any kind of Pure
expression described above). The same format is also used in ``with``,
``when`` and ``case`` expressions. In toplevel rules, ``with`` and
``case`` expressions, this basic form can also be augmented with a
condition ``if guard`` tacked on to the end of the rule, where ``guard``
is an integer expression which determines whether the rule is applicable.
Moreover, the keyword ``otherwise`` may be used to denote an empty guard
which is always true (this is syntactic sugar to point out the "default"
case of a definition; the interpreter just treats this as a comment). Pure
also provides some abbreviations for factoring out common left-hand or
right-hand sides in collections of rules; see the `Rule Syntax`_ section
for details.
ルール: ``lhs = rhs;``
書き換えルールは常に左辺パターン(単純な式であることが必要)と右辺(上で説明されているあらゆる種類の Pure 式)を結合します。同じフォーマットは ``with`` 、 ``when`` 、 ``case`` 式内でも使えます。トップレベルのルール、 ``with`` 式、 ``case`` 式という基本的な形式はそれぞれ ``if guard`` 条件を末尾に付けることができます。ここで ``guard`` というのは、ルールを適用してよいかどうかを示す整数式です。さらに、 ``otherwise`` キーワードを空の guard を示すものとして使うこともできます。 ``otherwise`` は常に真です(これは "default" ケースを示す糖衣構文です。インタープリタはこれを単にコメントと扱います)。 Pure はまた provides some abbreviations for factoring out common left-hand or right-hand sides in collections of rules; 詳しくは `Rule Syntax`_ セクションを参照して下さい。
Macro rules: ``def lhs = rhs;``
A rule starting with the keyword ``def`` defines a macro function. No
guards or multiple left-hand and right-hand sides are permitted
here. Macro rules are used to preprocess expressions on the right-hand
side of other definitions at compile time, and are typically employed to
implement user-defined special forms and simple kinds of optimization
rules. See the Macros_ section below for details and examples.
マクロルール: ``def lhs = rhs;``
``def`` キーワードで始まるルールはマクロ関数を定義します。この場合、条件ガードや複数の右辺・左辺は許されません。マクロルールは、コンパイル時に他の式の右辺をプリプロセスするために使われ、また典型的には、ユーザ定義の特別形や単純な最適化ルールを実装するために使われます。詳細と具体例は下部 Macros_ セクションを参照して下さい。
Global variable bindings: ``let lhs = rhs;``
Binds every variable in the left-hand side pattern to the corresponding
subterm of the right-hand side (after evaluating it). This works like a
``when`` clause, but serves to bind global variables occurring free on the
right-hand side of other function and variable definitions.
グローバル変数のバインディング: ``let lhs = rhs;``
左辺のパターン内にあるすべての変数を、右辺の下位項〔subterm〕に(まず評価を行ってから)結びつけます。これは ``when`` 節のように機能しますが、右辺に自由に現れる他の関数や変数定義をグローバル変数へ結びつけてくれます。
Constant bindings: ``const lhs = rhs;``
An alternative form of ``let`` which defines constants rather than
variables. (These are not to be confused with nonfix symbols which simply
stand for themselves!) Like ``let``, this construct binds the variable
symbols on the left-hand side to the corresponding values on the
right-hand side (after evaluation). The difference is that ``const``
symbols can only be defined once, and thus their values do not change
during program execution. This also allows the compiler to apply some
special optimizations such as constant folding.
定数バインディング
``let`` のもう一つの形で、変数でなく定数を定義します(この定数をノンフィクスシンボルと混同しないで下さい。ノンフィクスは単純にそれ自身を象徴し〔stand for〕ます!)。 ``let`` のように、この構造は左辺の変数シンボルを右辺の対応する値に(まず評価を行ってから)結びつけます。 ``const`` が ``let`` と異なるのは、 ``const`` は一度だけしか定義を行えないので、その値はプログラム実行中に変化しないという点です。これによりコンパイラは、例えば constant folding のような特別な最適化を行うことができます。
Toplevel expressions: ``expr;``
A singleton expression at the toplevel, terminated with a semicolon,
simply causes the given value to be evaluated (and the result to be
printed, when running in interactive mode).
トップレベル式: ``expre;``
トップレベルにある単独の式(セミコロンで終わる)は単純に、評価されるべき値を生じさせます(そして、対話モードで実行された場合は値が表示されます)。
Scoping Rules
-------------
A few remarks about the scope of identifiers and other symbols are in order
here. Like most modern functional languages, Pure uses `lexical` or `static`
binding for local functions and variables. What this means is that the binding
of a local name is completely determined at compile time by the surrounding
program text, and does not change as the program is being executed. In
particular, if a function returns another (anonymous or local) function, the
returned function captures the environment it was created in, i.e., it becomes
a (lexical) `closure`. For instance, the following function, when invoked with
a single argument ``x``, returns another function which adds ``x`` to its
argument:
識別子や他のシンボルのスコープについては、ここに若干の説明が揃っています。現代的な関数型言語のほとんどと同じように、 Pure ではローカルな関数と変数を `lexical` または `static` に束縛しています。この意味するところは、ローカルな名前の束縛はコンパイル時に周囲を取り巻くプログラムテキストと完全に境界を定められ、プログラムが実行されている間も変わることがありません。特に、もし関数がもう一つの(匿名の、あるいはローカルな)関数を返す場合、返される関数は自分が作り出された環境をキャプチャします。すなわち、それは(レキシカルな)クロージャとなるわけです。例えば、次の関数は、 ``x`` という引数とともに呼ばれると、引数に ``x`` を加算する関数を返します::
> foo x = bar with bar y = x+y end;
> let f = foo 99; f;
bar
> f 10, f 20;
109,119
This works the same no matter what other bindings of ``x`` may be in effect
when the closure is invoked:
クロージャが作動するときに他の ``x`` バインディングが有効であったとしても、このプログラムは同じように動作します::
> let x = 77; f 10, (f 20 when x = 88 end);
109,119
Global bindings of variable and function symbols work a bit differently,
though. Like many languages which are to be used interactively, Pure binds
global symbols `dynamically`, so that the bindings can be changed easily at
any time during an interactive session. This is mainly a convenience for
interactive usage, but works the same no matter whether the source code is
entered interactively or being read from a script, in order to ensure
consistent behaviour between interactive and batch mode operation.
ただし、グローバルな変数や関数シンボルの束縛は、やや違った動作をします。対話式で使われる多くの言語と同じように、 Pure はグローバルシンボルを `動的に` 束縛します。なので、束縛は対話的なセッションの間のいつでも簡単に変更できます。このことは主に対話式に使うとき便利ですが、ソースコードが対話的に入力された場合でも、スクリプトファイルから読み込まれた場合でも、同じように動作します。対話型処理でもバッチモード処理でも確実に一貫した振る舞いとなるよう、こうした動作になっています。
So, for instance, you can easily bind a global variable to a new value by just
entering a corresponding ``let`` command:
なので、例えば、グローバル変数に新たな値を束縛するには、対応する ``let`` コマンドを入力するだけで済みます::
> foo x = c*x;
> foo 99;
c*99
> let c = 2; foo 99;
198
> let c = 3; foo 99;
297
This works pretty much like global variables in imperative languages, but note
that in Pure the value of a global variable can only be changed with a ``let``
command at the toplevel. Thus referential transparency is unimpaired; while
the value of a global variable may change between different toplevel
expressions, it will always take the same value in a single evaluation.
これは命令型言語のグローバル変数とほぼ同じように動作します。 Pure のグローバル変数の値は最上位の ``let`` コマンドでのみ変更可能であることを覚えておいて下さい。したがって参照透過性は損なわれていません。あるグローバル変数の値は、最上位にある他の式と異なるかもしれませんが、それは一つの評価においていつも同じ値をとるでしょう。
Similarly, you can also add new equations to an existing function at any
time:
同様に、すでに存在する関数に新たな等式を追加することはいつでも可能です::
> fact 0 = 1;
> fact n::int = n*fact (n-1) if n>0;
> fact 10;
3628800
> fact 10.0;
fact 10.0
> fact 1.0 = 1.0;
> fact n::double = n*fact (n-1) if n>1;
> fact 10.0;
3628800.0
> fact 10;
3628800
(In interactive mode, it is even possible to completely erase a definition,
see section `Interactive Usage`_ for details.)
(対話モードでは定義そのものを完全に消去することさえ可能です。詳しくは `Interactive Usage`_ セクションを参照して下さい)。
So, while the meaning of a local symbol never changes once its definition has
been processed, toplevel definitions may well evolve while the program is
being processed, and the interpreter will always use the latest definitions at
a given point in the source when an expression is evaluated. This means that,
even in a script file, you have to define all symbols needed in an evaluation
before entering the expression to be evaluated.
なので、一度定義が処理されていればローカルシンボルの意味が二度と変わらないのに対し、最上位の定義はプログラムが処理される間に変化していく可能性が高くなり、またインタープリタは常に、式が評価される瞬間、ソースコードのその地点において最新の値を使います。これはつまり、たとえスクリプトファイル内であっても、その式の評価に必要な全てのシンボルを評価される前に定義しておかなければならないということです。
Rule Syntax
===========
ルール文法
Basically, the same rule syntax is used in all kinds of global and local
definitions. However, some constructs (specifically, ``when``, ``let``,
``const`` and ``def``) use a restricted rule syntax where no guards or
multiple left-hand and right-hand sides are permitted. When matching against a
function or macro call, or the subject term in a ``case`` expression, the
rules are always considered in the order in which they are written, and the
first matching rule (whose guard evaluates to a nonzero value, if applicable)
is picked. (Again, the ``when`` construct is treated differently, because each
rule is actually a separate definition.)
基本的に、グローバルorローカルなあらゆる種類の定義に使われるルール文法はすべて同じです。しかし、いくつかの構造(特に ``when``, ``let``, ``const``, ``def``)は厳格なルール文法を使います。これらはガードや複数の右辺・左辺を許容しません。関数やマクロ呼び出しに対するマッチングを行うとき、または ``case`` 式内の subject term に対してマッチングをときは、常にそれらが書かれている順番通りだと考えられ、またファースト・マッチング・ルール(whose guard evaluates to a nonzero value, if applicable)が選ばれます。(もう一度、 ``when`` 構造の扱いは異なります。それぞれのルールが実際には独立して定義されているためです)
Patterns
--------
パターン
The left-hand side of a rule is a special kind of simple expression, called a
`pattern`. Patterns consist of function and operator applications as well as
any of the "atomic" expression types (symbols, numbers, strings and list
values). *Not* permitted are any of the special expression types (lambda,
``case``, ``when``, ``with``, conditional expressions, as well as list and
matrix comprehensions). For technical reasons, the current implementation also
forbids matrix values in patterns, but it is possible to match a matrix value
as a whole using the ``matrix`` type tag, see below.
ルールの左辺は特別な種類の単独式で、 `pattern` と呼ばれます。パターンは関数、演算子アプリケーション、およびあらゆる "atomic" な式タイプ(シンボル、数値、文字列、リストなどの値)から構成されます。しかし左辺値に特別な式タイプ(ラムダ、 ``case``、``when``、``with``、条件式、リスト内包、マトリクス内包)を使うことは許されません。技術的な理由から、現在の実装ではパターン内でマトリクス値を使うことも禁止されています。しかしながら ``matrix`` 型タグを使ってマトリクス値全体をマッチさせることは可能です。詳しくは下部を参照して下さい。
As already mentioned, the '``_``' symbol is special in patterns; it denotes
the `anonymous variable` which matches an arbitrary value (independently for
all occurrences) without actually binding a variable. For instance:
すでに述べた通り、 '``_``' シンボルはパターン内で特別な意味を持ちます。 '``_``' は `無名変数` を示し、任意の値に(independently for all occurrences)マッチして、変数に束縛されることはありません。例えば::
foo _ _ = 0;
This will match the application of ``foo`` to any combination of two
arguments (and just ignore the values of these arguments).
この場合、2つの引数がどんな組み合わせであっても ``foo`` が適用されます(引数の値はただ無視されます)。■ignore がどういう挙動か要チェック■
Constants in patterns must be matched literally. For instance:
パターン内の定数はリテラルにマッチされなければいけません■意味不明■。例えば::
foo 0 = 1;
This will only match an application of ``foo`` to the machine integer ``0``,
not ``0.0`` or ``0L`` (even though these compare equal to ``0`` using the
'``==``' operator).
この場合、 ``foo`` が machine integer ``0`` へ適用されている場合に限りマッチします。 ``0.0`` や ``0L`` にはマッチしません('``==``' 演算子を使って両者を ``0`` と比較するとイコールですが、だとしてもマッチしないのです)。
In difference to Haskell, patterns may contain repeated variables (other than
the anonymous variable), i.e., they may be `non-linear`. Thus rules like the
following are legal in Pure, and will only be matched if all occurrences of
the same variable in the left-hand side pattern are matched to the same
value:
Haskell と違って、パターンに繰り返しの値を含めることができます(無名配列のほかに)。すなわち、パターンは `非線形` になる可能性があります。したがって、次に示すようなルールは Pure では合法的なものです::
> foo x x = x;
> foo 1 1;
1
> foo 1 2;
foo 1 2
Non-linear patterns are particularly useful for computer algebra where you
will frequently encounter rules such as the following:
もしあなたが次のようなルールと頻繁に出会うようなら、非線形のパターンは計算機代数のために特に役立つものとなります::
> x*y+x*z = x*(y+z);
> a*(3*4)+a*5;
a*17
.. _same: purelib.html#same
.. |same| replace:: ``same``
The notion of "sameness" employed here is that of syntactical identity, which
means that the matched subterms must be identical in structure and content.
The prelude provides syntactic equality as a function |same|_ and a comparison
predicate '``===``'. Thus the above definition of ``foo`` is roughly
equivalent to the following:
ここで「同じさ」という言葉を使って示そうとしているのは、文法的な一致であり、 matched subterm は構造的にも内容的にも同じでなければなりません。 prelude は文法的な等しさ〔equality〕を |same|_ 関数と '===' 演算子で提供しています。なので、上で示した ``foo`` の定義は大まかに次の表現と等価です::
foo x y = x if same x y;
It is important to note the differences between syntactic equality embodied by
``same`` and '``===``', and the "semantic" equality operator '``==``'. The
former are always defined on all terms, whereas '``==``' is only available on
data where it has been defined explicitly, either in the prelude or by the
programmer. Also note that '``==``' may assert that two terms are equal even
if they are syntactically different. Consider, e.g.:
``same`` や '``===``' が表す文法的な等しさと、等値演算子 '``==``' が表す意味的な等しさとの間にある違いに注意しておく必要があります。前者があらゆる項に対して定義されているのに対して、'``==``' はデータ(prelude 内かプログラマーによって明確に定義づけられている)に対してしか使えません。また '``==``' は、たとえ両項が文法的に異なっていても両者が「等しい」と断言します。次の例を考えてみて下さい::
> 0==0.0;
1
> 0===0.0;
0
This distinction is actually quite useful. It gives the programmer the
flexibility to define '``==``' in any way that he sees fit, which is
consistent with the way the other comparison operators like '``<``' and
'``>``' are handled in Pure.
この違いは非常に実用的です。プログラマーがフィットすると思うやり方で '``==``' を定義する柔軟性を与えてくれます。これは Pure が '``<``' や '``>``' など他の比較演算子を扱う方法と矛盾しません。
Patterns may also contain the following special elements which are not
permitted in right-hand side expressions:
* A Haskell-style `"as" pattern` of the form *variable* ``@`` *pattern*
binds the given variable to the expression matched by the subpattern
*pattern* (in addition to the variables bound by *pattern* itself). This
is convenient if the value matched by the subpattern is to be used on the
right-hand side of an equation.
* Haskellライクな *変数* ``@`` *パターン* という形式の `"as" パターン` は、与えられた変数を、サブパターン *パターン* にマッチする式へ結びつけます(*パターン* そのものにより結びつけられる変数に加えて)。サブパターンにマッチする値を等式右辺で使う場合に便利です。
* A left-hand side variable (including the anonymous variable) may be followed
by a `type tag` of the form ``::`` *name*, where *name* is either one
of the built-in type symbols ``int``, ``bigint``, ``double``, ``string``,
``matrix``, ``pointer``, or an existing identifier denoting a custom
constructor symbol for a user-defined data type. The variable can then match
only values of the designated type. Thus, for instance, '``x::int``'
only matches machine integers. See the `Type Tags`_ section below for
details.
* 左辺の変数(無名変数を含む)の後に ``::`` *名前* という形式の `型タグ` を付けることも可能です。 *名前* 部分には、組み込み型シンボル ``int``, ``bigint``, ``double``, ``string``, ``matrix``, ``pointer`` か、あるいはユーザ定義のデータ型を示す識別子のいずれかが入ります。このとき変数は、示された型の値にだけマッチすることになります。だから例えば '``x::int``' は machine integers だけにマッチします。詳しくは下部 `Type Tags`_ セクションを参照して下さい。
Syntactically, both "as" patterns and type tags are primary expressions. If
the subpattern of an "as" pattern is a compound expression, it *must* be
parenthesized. For instance, the following function duplicates the head
element of a list:
文法的には "as" パターンも型タグも primary expressions です。もし "as" パターンのサブパターンが合成式である場合、その式は丸括弧で囲われ *なければいけません* 。例えば、次の関数はリストの先頭要素を複製します::
foo xs@(x:_) = x:xs;
Note that if you accidentally forget the parentheses around the subpattern
``x:_``, you still get a syntactically correct definition:
もしあなたがサブパターン ``x:_`` を丸括弧で囲うのを忘れてしまった場合、まだ文法的には正しい定義になるでしょう::
foo xs@x:_ = x:xs;
But this gets parsed as ``(foo xs@x):_ = x:xs``, which is most certainly *not*
what you want. It is thus a good idea to just always enclose the subpattern
with parentheses in order to prevent such glitches.
しかし、これは ``(foo xs@x):_ = x:xs`` という表現と同等に解釈されます。まず間違いなくあなたが求めるものでは *ない* でしょう。なので、こんな厄介な事態を避けるため、いつでもサブパターンを丸括弧で囲うようにしておくのは良い心がけです。
Another potential pitfall is that the notation ``foo::bar`` is also used to
denote "qualified symbols" in Pure, cf. Namespaces_. Usually this will be
resolved correctly, but if ``foo`` happens to also be a valid namespace then
most likely you'll get an error message about an undeclared symbol. You can
always work around this by adding spaces around the '``::``' symbol, as in
``foo :: bar``. Spaces are never permitted in qualified symbols, so this makes
it clear that the construct denotes a type tag.
もうひとつ陥りがちな落とし穴として、Pure において ``foo::bar`` という書き方は ``型指定されたシンボル`` を示すためにも使われる点があります(cf. Namespaces_)。だいたいの場合は正しく解決されますが、もし ``foo`` が有効な名前空間である場合、
Type Tags
---------
型タグ
Type tags are really nothing but a special form of "as" patterns which
restrict variables to given data "domains". Like Lisp, Pure is essentially a
typeless language and doesn't really have a notion of "data types"; all data
belongs to the same universe of terms. Thus the only way to restrict the type
of values which can be matched by a variable is to provide an "as" pattern
which matches objects of the desired domain and nothing else. However, in the
special case of the built-in types (machine and big integers, double values,
strings, matrices and pointers) there is no way to spell out all
"constructors", as there are infinitely many (or none, as in the case of
``matrix`` and ``pointer`` which are constructed and inspected using special
primitives, but are otherwise "opaque" at the Pure level). As a remedy, an
appropriate type tag makes it possible to match these values.
型タグは "as" パターンの特別な形、以外の何者でもありません。つまり、変数を、指定されたデータ「ドメイン」に限定します。 Pure は Lisp と同じように型のない言語で、「データ型」の記法はありません。すべてのデータは同じ universe of terms に属しています。そのため、ある変数によってマッチされうる値の型を制限するには "as" パターンを与えるしかありません。 "as" パターンを持つ値は、求めるドメインを持つオブジェクトにのみマッチし、他とはしません。しかし、組み込み型の特別なケース(machine and big integers, double 値, 文字列、マトリクス、ポインタ)では、全ての "constructors" を spell out する方法はありません。なぜならそれは無限に多いからです(または、マトリクスとポインタが construct され、special primitives を使って inspect された場合は、何もないことになります。しかしそうでない場合は Pure レベルでは "opaque" です)。改善策としては、適切な型タグを付けることでそうした値にマッチさせることができます。
In order to generalize this to user-defined domains of data, Pure adopts the
convention that any other tagged variable ``x::bar`` is just a shorthand for
the "as" pattern ``x@(bar _)``. Thus a custom data type can be represented by
designating a special constructor symbol (``bar`` in the above example) which
takes the actual data as its single argument. This works the same no matter
what the internal structure of the data is (which in many cases you wouldn't
want to depend on anyway, for the sake of data abstraction).
これをユーザ定義ドメインのデータに一般化するために、 Pure では次のような慣習を適用しています。つまり、あらゆるタグ付き変数 ``x::bar`` は単に "as" パターン ``x@(bar _)`` の略記法にすぎないというものです。したがって、カスタムデータ型は特別なコンストラクタシンボルを作ることによって表されます(上の例では ``bar`` がそれに当たります)。カスタムデータ型となるコンストラクタシンボルは、実際のデータを単独の引数としてとります。この仕組みは、データの内部構造に関わらず同じように動作します(多くの場合、データ型抽象化の便宜をはかるでしょうから、内部構造に依存してしまうのは望まれないことでしょう)。
Note that this is merely a convention, but it works reasonably well and makes
up for the fact that Pure doesn't support data types at the language level.
For instance, we might represent points in the plane using a constructor
symbol ``Point`` which gets applied to pairs of coordinates. We equip this
data type with an operation ``point`` to construct a point from its
coordinates, and two operations ``xcoord`` and ``ycoord`` to retrieve the
coordinates:
このことは慣習であるにすぎないと覚えておいて下さい。しかしこれは非常に合理的に動作し、Pure が言語レベルではデータ型をサポートしていないことの代わりになってくれます。例えば ``Point`` というコンストラクタシンボルを使って平面上の点を表したいとしましょう。このコンストラクタは座標のペアに対して適用されます。私たちは ``point`` という処理によって座標ペアから点を構築し〔construct〕、また ``xcoord`` と ``ycoord`` という2つの処理によって座標を取り戻すことにします::
point x y = Point (x,y);
xcoord (Point (x,y)) = x;
ycoord (Point (x,y)) = y;
Now we might define a function ``translate`` which shifts the coordinates of a
point by a given amount in the x and y directions as follows:
今や私たちは、x 方向と y 方向に指定した量だけ点の座標を動かす ``translate`` 関数を定義することができます。次のように::
translate (x,y) p::Point = point (xcoord p+x) (ycoord p+y);
Note the use of ``Point`` as a type tag on the ``p`` variable. By these means,
we can ensure that the argument is actually an instance of the point data
type, without knowing anything about the internal representation. We can use
these definitions as follows:
``p`` 変数に対して ``Point`` を型タグとして使っていることに注目して下さい。このような方法で、内部的なデータ表現について何も知らなくても、引数が実際に point データ型であることを保証できます。このような定義を次のように使うことも可能です::
> let p::Point = point 3 3;
> p; translate (1,2) p;
Point (3,3)
Point (4,5)
Some data types in Pure's standard library (specifically, the container data
types) are actually represented in this fashion, see the `Pure Library
Manual`_ for details.
Pure の標準ライブラリにあるいくつかのデータ型(特に container データ型)は、実際このやり方で表されています。詳しくは `Pure Library Manual`_ を参照して下さい。
General Rules
-------------
The most general type of rule, used in function definitions and ``case``
expressions, consists of a left-hand side pattern, a right-hand side
expression and an optional guard. The left-hand side of a rule can be omitted
if it is the same as for the previous rule. This provides a convenient means
to write out a collection of equations for the same left-hand side which
discriminates over different conditions:
関数宣言と ``case`` 式で使われる最も一般的なタイプのルールは、左辺にパターンがあり、右辺に式と(オプションの)条件ガードで構成されます。ルールの左辺が直前のルールと同じ場合は省略できます。これは、同じ左辺に対して、異なる条件で場合分けされた等式の集まりを書くのに便利です::
lhs = rhs if guard;
= rhs if guard;
...
= rhs otherwise;
For instance:
例えば::
fact n = n*fact (n-1) if n>0;
= 1 otherwise;
Pure also allows a collection of rules with different left-hand sides but the
same right-hand side(s) to be abbreviated as follows:
また Pure では、左辺は異なるが右辺は同じ等式の集まりを、次のように省略して書くことも許しています::
lhs |
...
lhs = rhs;
This is useful if you need different specializations of the same rule which
use different type tags on the left-hand side variables. For instance:
同じルールの左辺の変数に異なる型タグを使い、それぞれ違った特別化を行いたい場合に便利です。例えば::
fact n::int |
fact n::double |
fact n = n*fact(n-1) if n>0;
= 1 otherwise;
In fact, the left-hand sides don't have to be related at all, so that you can
also write something like:
実際のところ、左辺にある複数の式はまったく関連づけられていません。そのため次のように書くこともできます::
foo x | bar y = x*y;
However, this construct is most useful when using an "as" pattern to bind a
common variable to a parameter value after checking that it matches one of
several possible argument patterns (which is slightly more efficient than
using an equivalent type-checking guard). E.g., the following definition binds
the ``xs`` variable to the parameter of ``foo``, if it is either the empty
list or a list starting with an integer:
しかし、こうした構造が最も便利なのは、 共通の変数をパラメータ値に束縛するために "as" パターンを使う場合でしょう。パラメータ値がいくつかの引数パターンにマッチするか試された後で束縛されます(これは等価な型チェックガードを使うよりも少しだけ効率的です)。例えば、もしそれが空リストか整数で始まるものである場合は::
foo xs@[] | foo xs@(_::int:_) = ... xs ...;
The same construct also works in ``case`` expressions, which is convenient if
different cases should be mapped to the same value, e.g.:
同じ構造は ``case`` 式でも機能します。異なるケースでも同じ値にマップさせたいときに便利です::
case ans of "y" | "Y" = 1; _ = 0; end;
Sometimes it is useful if local definitions (``when`` and ``with``) can be
shared by the right-hand side and the guard of a rule. This can be done by
placing the local definitions behind the guard, as follows (we only show the
case of a single ``when`` clause here, but of course there may be any number
of ``when`` and ``with`` clauses behind the guard):
ローカル定義( ``when`` と ``with`` )がルール右辺とガードで共有されうる場合、これは役立ちます::
lhs = rhs if guard when defns end;
Note that this is different from the following, which indicates that the
definitions only apply to the guard but not the right-hand side of the rule:
この例が次の例と異なることに注意して下さい。次の例では、定義がガードだけに限って適用され、ルール右辺には適用されないことを示しています::
lhs = rhs if (guard when defns end);
Conversely, definitions placed *before* the guard only apply to the right-hand
side but not the guard (no parentheses are required in this case):
逆に、ガードの *前に* 置かれた定義は右辺にのみ適用され、ガードには適用されません(この場合、丸括弧は必要ありません)::
lhs = rhs when defns end if guard;
An example showing the use of a local variable binding spanning both the
right-hand side and the guard of a rule is the following quadratic equation
solver, which returns the (real) solutions of the equation ``x^2+p*x+q = 0``
if the discriminant ``d = p^2/4-q`` is nonnegative:
ローカル変数の束縛を、ルールの右辺とガードの両方にまたがらせる例として、二次方程式を解く関数を次に示します。この関数は、もし ``d = p^2/4-q`` の判別式が負でなければ ``x^2+p*x+q = 0`` という等式の実数解を返します::
> using math;
> solve p q = -p/2+sqrt d,-p/2-sqrt d if d>=0 when d = p^2/4-q end;
> solve 4 2; solve 2 4;
-0.585786437626905,-3.41421356237309
solve 2 4
Note that the above definition leaves the case of a negative discriminant
undefined.
この定義は、判別式が負である場合を未定義のままにしていることに注目して下さい。
Simple Rules
------------
As already mentioned, ``when``, ``let`` and ``const`` use a simplified kind of
rule syntax which just consists of a left-hand and a right-hand side separated
by the equals sign. In this case the meaning of the rule is to bind the
variables in the left-hand side of the rule to the corresponding subterms of
the value of the right-hand side. This is also called a `pattern binding`.
Guards or multiple left-hand or right-hand sides are not permitted in these
rules. However, it is possible to omit the left-hand side if it is just the
anonymous variable '``_``' by itself, indicating that you don't care about the
result. The right-hand side is still evaluated, if only for its side-effects,
which is handy, e.g., for adding debugging statements to your code. For
instance, here is a variation of the quadratic equation solver which also
prints the discriminant after it has been computed::
> using math, system;
> solve p q = -p/2+sqrt d,-p/2-sqrt d if d>=0
> when d = p^2/4-q; printf "The discriminant is: %g\n" d; end;
> solve 4 2;
The discriminant is: 2
-0.585786437626905,-3.41421356237309
> solve 2 4;
The discriminant is: -3
solve 2 4
Note that simple rules of the same form ``lhs = rhs`` are also used in macro
definitions (``def``), to be discussed in the `Macros`_ section. In this case,
however, the rule denotes a real rewriting rule, not a pattern binding, hence
the left-hand side is mandatory in these rules.
Examples
========
具体例
Here are a few examples of simple Pure programs.
シンプルな Pure プログラムの例をいくつかここで示します。
The factorial:
階乗::
fact n = n*fact (n-1) if n>0;
= 1 otherwise;
let facts = map fact (1..10); facts;
The Fibonacci numbers:
フィボナッチ数::
fib n = a when a,b = fibs n end
with fibs n = 0,1 if n<=0;
= case fibs (n-1) of
a,b = b,a+b;
end;
end;
let fibs = map fib (1..30); fibs;
It is worth noting here that Pure performs tail call optimization so that
tail-recursive definitions like the following will be executed in constant
stack space (see `Stack Size and Tail Recursion`_ in the `Caveats and Notes`_
section for more details on this):
Pure が tail call optimization を行うことはここでとても価値あることです。このおかげで次のような末尾再帰の定義を一定のスタック領域で実行できます(詳細は `Caveats and Notes`_ セクション内の `Stack Size and Tail Recursion`_ 部を参照して下さい)。::
// tail-recursive factorial using an "accumulating parameter"
fact n = loop 1 n with
loop p n = if n>0 then loop (p*n) (n-1) else p;
end;
Here is an example showing how constants are defined and used. Constant
definitions take pretty much the same form as variable definitions with
``let`` (see above), but work more like the definition of a parameterless
function whose value is precomputed at compile time:
以下の例は、定数を定義し、使用する方法を示したものです。定数定義は変数定義とほとんどまったく同じように ``let`` 形式を使います(上部を参照)。しかし定数はむしろ、引数を取らず値がコンパイル時に計算される関数のように動作します::
> extern double atan(double);
> const pi = 4*atan 1.0;
> pi;
3.14159265358979
> foo x = 2*pi*x;
> show foo
foo x = 6.28318530717959*x;
Note that the compiler normally computes constant subexpression at compile
time, such as ``2*pi`` in the ``foo`` function. This works with all simple
scalars (machine ints and doubles), see `Constant Definitions`_ for details.
コンパイラは通常、定数に含まれる下位式(この例では ``2*pi`` など)をコンパイル時に計算することを覚えておいて下さい。単純スカラー(machine int と double)に対してはすべてこのように動作します。詳しくは `Constant Definitions`_ を参照して下さい。
List Comprehensions
-------------------
リスト内包
List comprehensions are Pure's main workhorse for generating and processing
all kinds of list values. Here's a well-known example, a variation of
Erathosthenes' classical prime sieve:
リスト内包は Pure であらゆる種類のリスト値を生成し、処理するための main workhorse です。ここに掲げるのはよく知られた例で、エラトステネスの篩で素数を発見する古典的アルゴリズムの変形である::
primes n = sieve (2..n) with
sieve [] = [];
sieve (p:qs) = p : sieve [q | q = qs; q mod p];
end;
(This definition is actually rather inefficient, there are much better albeit
more complicated implementations of this sieve.)
(この定義は実用上では非効率なもので、もっと複雑だが効率的な実装がある。)
For instance:
例えば::
> primes 100;
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
If you dare, you can actually have a look at the catmap-lambda-if-then-else
expression the comprehension expanded to:
その気があるなら、 catmap-lambda-if-then-else 式で内包を拡張した例を見てみることもできます::
> show primes
primes n = sieve (2..n) with sieve [] = []; sieve (p:qs) = p:sieve
(catmap (\q -> if q mod p then [q] else []) qs) end;
List comprehensions are also a useful device to organize backtracking
searches. For instance, here's an algorithm for the n queens problem, which
returns the list of all placements of n queens on an n x n board (encoded as
lists of n pairs (i,j) with i = 1..n), so that no two queens hold each other
in check:
リスト内包は、バックトラック探索を組み立てるのに便利でもあります。例えば次の例は n クイーン問題を解くアルゴリズムで、 n x n のボード上に置かれた全ての n クイーンのリストを返します(encoded as lists of n pairs (i,j) with i = 1..n)。結果、2つのクイーンがチェック内で互いをホールドすることはない。■この段落全面見直し■::
queens n = search n 1 [] with
search n i p = [reverse p] if i>n;
= cat [search n (i+1) ((i,j):p) | j = 1..n; safe (i,j) p];
safe (i,j) p = ~any (check (i,j)) p;
check (i1,j1) (i2,j2)
= i1==i2 || j1==j2 || i1+j1==i2+j2 || i1-j1==i2-j2;
end;
(Again, this algorithm is rather inefficient, see the examples included in the
Pure distribution for a much better algorithm by Libor Spacek.)
(またまた、このアルゴリズムは非効率です。 Libor Spacek によるもっと効率的なアルゴリズムの例が Pure ディストリビューションに同梱されているので、そちらを参照)
Lazy Evaluation and Streams
---------------------------
遅延評価とストリーム
As already mentioned, lists can also be evaluated in a "lazy" fashion, by just
turning the tail of a list into a future. This special kind of list is also
called a `stream`. Streams enable you to work with infinite lists (or finite
lists which are so huge that you would never want to keep them in memory in
their entirety). E.g., here's one way to define the infinite stream of all
Fibonacci numbers:
すでに述べた通り、リストは「怠惰な」やり方で評価されることも可能です。ただリストの末尾を未来へと向けてやればよいのです。この特殊なリストは `ストリーム` とも呼ばれます。ストリームを使えば、あなたは無限長のリストを扱うこともできるようになります(あるいは有限なリストであっても、あまりに大きくてその全体をメモリ上に保存したいと思わないケースもあるでしょう)。例えば、全フィボナッチ数を含む無限長ストリームを定義する方法の一つをここに示します::
> let fibs = fibs 0L 1L with fibs a b = a : fibs b (a+b) & end;
> fibs;
0L:#<thunk 0xb5d54320>
Note the ``&`` on the tail of the list in the definition of the local ``fibs``
function. This turns the result of ``fibs`` into a stream, which is required
to prevent the function from recursing into samadhi. Also note that we work
with bigints in this example because the Fibonacci numbers grow quite rapidly,
so with machine integers the values would soon start wrapping around to
negative integers.
ローカルな ``fibs`` 関数のリスト末尾にある ``&`` に注目して下さい。これが ``fibs`` の結果をストリームへと変えてくれます。この関数が再帰的な瞑想に陥るのを防ぐにはこれが必要です。また、私たちはこの例で bigint を扱っていることにも注目して下さい。フィボナッチ数はすぐに大きくなり、machine integer を使っているとすぐに負の整数側に回り込んでしまうでしょう。
Streams like these can be worked with in pretty much the same way as with
lists. Of course, care must be taken not to invoke "eager" operations such as
``#`` (which computes the size of a list) on infinite streams, to prevent
infinite recursion. However, many list operations work with infinite streams
just fine, and return the appropriate stream results. E.g., the ``take``
function (which retrieves a given number of elements from the front of a list)
works with streams just as well as with "eager" lists:
このようなストリームは通常のリストとまったく同じ方法で扱うことができます。もちろん、無限に繰り返される処理を避けるため、 ``#`` (リストの長さを計算する)のような「熱心な」処理を始めないよう気をつける必要はあります。しかし、リスト処理の多くは無限長のストリームでもうまく処理できますし、適切な結果ストリームを返してくれます。例えば ``take`` 関数(与えられた数の要素をリストの先頭から取得する)はストリームを処理する場合でも「熱心な」(先行評価の)リストと同じようにうまくやってくれます::
> take 10 fibs;
0L:#<thunk 0xb5d54350>
Hmm, not much progress there, but that's just how streams work (or rather they
don't, they're lazy bums indeed!). Nevertheless, the stream computed with
``take`` is in fact finite and we can readily convert it to an ordinary list,
forcing its evaluation:
うーん、うまくいきませんね。でもこれがストリームの働き方なんです(もしかしたら、ずっとやらないかもしれません、なんせ怠惰なろくでなしなので!)。でも、 ``take`` で計算されたストリームは実際には有限で、強制的に評価してやれば普通のリストへと簡単に変換できます::
> list (take 10 fibs);
[0L,1L,1L,2L,3L,5L,8L,13L,21L,34L]
An easier way to achieve this is to cut a "slice" from the stream:
もっと簡単に実現するなら、ストリームから「スライス」を切り取ります::
> fibs!!(0..10);
[0L,1L,1L,2L,3L,5L,8L,13L,21L,34L,55L]
Also note that since we bound the stream to a variable, the already computed
prefix of the stream has been memoized, so that this portion of the stream is
now readily available in case we need to have another look at it later. By
these means, possibly costly reevaluations are avoided, trading memory for
execution speed:
私たちはストリームを変数に束縛したので、ストリームのうちすでに計算されたプレフィクスは記憶されていることを忘れないで下さい。なので、ストリームのこの部分をあとから使いたい場合でも簡単に使える状態になっています。この方法で実行速度とメモリーを取り引きすれば、コストがかかる可能性のある再評価を避けることができます::
> fibs;
0L:1L:1L:2L:3L:5L:8L:13L:21L:34L:55L:#<thunk 0xb5d54590>
Let's take a look at some of the other convenience operations for generating
stream values. The prelude defines infinite arithmetic sequences, using
``inf`` or ``-inf`` to denote an upper (or lower) infinite bound for the
sequence, e.g.:
さあ、ストリームの値を生成する便利な処理を他にも見てみましょう。 prelude は無限大の数列を定義します。そこでは ``inf`` または ``-inf`` をその数列に束縛し、正の(or 負の)無限大を示すのに使うことができます::
> let u = 1..inf; let v = -1.0:-1.2..-inf;
> u!!(0..10); v!!(0..10);
[1,2,3,4,5,6,7,8,9,10,11]
[-1.0,-1.2,-1.4,-1.6,-1.8,-2.0,-2.2,-2.4,-2.6,-2.8,-3.0]
Other useful stream generator functions are ``iterate``, which keeps applying
the same function over and over again, ``repeat``, which just repeats its
argument forever, and ``cycle``, which cycles through the elements of the
given list:
他の便利なストリーム生成関数として ``iterate`` があります。これは同じ関数を何度も何度も適用しつづけます。また ``repeat`` は、与えられた引数を永遠に繰り返します。 ``cycle`` は与えられたリストの要素を循環させます::
> iterate (*2) 1!!(0..10);
[1,2,4,8,16,32,64,128,256,512,1024]
> repeat 1!!(0..10);
[1,1,1,1,1,1,1,1,1,1,1]
> cycle [0,1]!!(0..10);
[0,1,0,1,0,1,0,1,0,1,0]
Moreover, list comprehensions can draw values from streams and return the
appropriate stream result:
さらに、リスト内包はストリームから値を引き出し、対応する結果ストリームとして返すことができます::
> let rats = [m,n-m | n=2..inf; m=1..n-1; gcd m (n-m) == 1]; rats;
(1,1):#<thunk 0xb5d54950>
> rats!!(0..10);
[(1,1),(1,2),(2,1),(1,3),(3,1),(1,4),(2,3),(3,2),(4,1),(1,5),(5,1)]
Finally, let's rewrite our prime sieve so that it generates the infinite
stream of *all* prime numbers:
最後に、この節の最初で書いた素数の篩を書き直して、 *全* 素数を含む無限長のリストを生成するようにしましょう::
all_primes = sieve (2..inf) with
sieve (p:qs) = p : sieve [q | q = qs; q mod p] &;
end;
Note that we can omit the empty list case of ``sieve`` here, since the sieve
now never becomes empty. Example:
ここでは ``sieve`` の空リストのケースを省略できることに注目して下さい。なぜなら、この篩が空になることはもうないからです。具体例::
> let P = all_primes;
> P!!(0..20);
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73]
> P!299;
1987
You can also just print the entire stream. This will run forever, so hit
``Ctrl-C`` when you get bored:
ストリーム全体を出力することもできます。これは永遠に走り続けるので、飽きたところで ``Ctrl-C`` を押して下さい::
> using system;
> do (printf "%d\n") all_primes;
2
3
5
...
(Make sure that you really use the ``all_primes`` function instead of the
``P`` variable to print the stream. Otherwise, because of memoization the
stream stored in ``P`` will grow with the number of elements printed until
memory is exhausted. Calling ``do`` on a fresh instance of the stream of
primes allows ``do`` to get rid of each "cons" cell after having printed the
corresponding stream element.)
(ストリームを出力するときは必ず ``P`` 変数ではなく ``all_primes`` 関数を直接出力に使うようにして下さい。そうしないと要素が記憶されてしまうので、 ``P`` に保存されるストリームが表示される要素の数だけ大きくなり、最後にはメモリを使い果たすでしょう。作ったばかりの素数ストリームインスタンスに対して ``do`` を呼び出すと、あるストリーム要素を表示したあと、対応する "cons" cell を ``do`` が取り除いていってくれます)
Matrix Computations
-------------------
マトリクス計算
Pure offers a number of basic matrix operations, such as matrix construction,
indexing, slicing, as well as getting the size and dimensions of a matrix
(these are briefly described in the `Standard Library`_ section
below). However, it does *not* supply built-in support for matrix arithmetic
and other linear algebra algorithms. The idea is that these can and should be
provided through separate libraries (please check the Pure website for the
pure-gsl module which is an ongoing project to provide a full GSL interface
for the Pure language).
Pure は基本的なマトリクス処理を数多く提供します。例えばマトリクスの構築、indexing、スライス、マトリクスの大きさや次元を得ることなどです(これらは下部 `Standard Library`_ セクションで詳しく説明されています)。しかし、マトリクス計算や他の代数アルゴリズムは組み込みでは提供され *ません* 。これらは独立したライブラリで提供可能であり、またそうすべきであるという考えからです(Pure ウェブサイトで pure-gsl モジュールをチェックしてみてください。Pure 言語に完全な GSL インターフェースを提供しようとする現在進行中のプロジェクトです)。
But Pure's facilities for matrix and list processing also make it easy to roll
your own, if desired. First, the prelude provides matrix versions of the
common list operations like ``map``, ``fold``, ``zip`` etc., which provide a
way to implement common matrix operations. E.g., multiplying a matrix ``x``
with a scalar ``a`` amounts to mapping the function ``(a*)`` to x, which
can be done as follows:
しかし Pure はマトリクスやリストを容易に扱えるよう整備されているので、お望みなら自分でそれを作るのも簡単です。まず、 prelude は、よく使うリスト処理( ``map``, ``fold``, ``zip`` 等々)のマトリクス版を提供します。これらは共通のリスト処理を実装する手段を提供します。例えば、マトリクス ``x`` にスカラー ``a`` の数を掛けることは ``(a*)`` 関数を x に適用することに相当する、というルールは以下のように実現できます::
> a * x::matrix = map (a*) x if ~matrixp a;
> 2*{1,2,3;4,5,6};
{2,4,6;8,10,12}
Likewise, matrix addition and other element-wise operations can be realized
using ``zipwith``, which combines corresponding elements of two matrices using
a given binary function:
さらに、マトリクスの加算や、エレメントに関する他の処理は ``zipwith`` を使って実現できます。これは、2つのマトリクスの互いに対応する要素を、与えられた関数を使って結合します:
> x::matrix + y::matrix = zipwith (+) x y;
> {1,2,3;4,5,6}+{1,2,1;3,2,3};
{2,4,4;7,7,9}
Second, matrix comprehensions make it easy to express a variety of algorithms
which would typically be implemented using ``for`` loops in conventional
programming languages. To illustrate the use of matrix comprehensions, here is
how we can define an operation to create a square identity matrix of a given
dimension:
2番目に、マトリクス内包は様々なアルゴリズムの表現を容易にしてくれます。よくあるプログラミング言語では、典型的には ``for`` ループを使ってこのようなアルゴリズムを実装しています。マトリクス内包の使い方を例示するするため、与えられた大きさの正方行列を作り出す処理を定義する方法をここで示します::
> eye n = {i==j | i = 1..n; j = 1..n};
> eye 3;
{1,0,0;0,1,0;0,0,1}
Note that the ``i==j`` term is just a Pure idiom for the Kronecker
symbol. Another point worth mentioning here is that the generator clauses of
matrix comprehensions alternate between row and column generation
automatically, if values are drawn from lists as in the example above. (More
precisely, the last generator, which varies most quickly, yields a row, the
next-to-last one a column of these row vectors, and so on.) This makes matrix
comprehensions resemble customary mathematical notation very closely.
``i==j`` 項はクロネッカー記号を表すための Pure のイディオムだと覚えておいて下さい。もう一つ触れておいたほうが良さそうな点は、上の例のようにリストから値が取り出される場合、マトリクス内包のジェネレータ節は行と列の生成を自動で交互に行うということです(より正確に言えば、最後のジェネレータは(最初に変化するわけですが)行を生成し、the next-to-last one a column of these row vectors, and so on.)。このことは、マトリクス内包を、数学の慣習的な記述と非常に似たものにしています。
Of course, matrix comprehensions can also draw values from other matrices
instead of lists. In this case the block layout of the component matrices is
preserved. For instance:
もちろん、マトリクス内包は他のマトリクスからリストでなくマトリクスを取り出すこともできます。この場合、要素となるマトリクスのブロックレイアウトは保たれます。例えば::
> {x,y|x={1,2};y={a,b;c,d}};
{(1,a),(1,b),(2,a),(2,b);(1,c),(1,d),(2,c),(2,d)}
Note that a matrix comprehension involving filters may fail because the
filtered result isn't a rectangular matrix any more. E.g.,
``{2*x|x={1,2,3,-4};x>0}`` works, as does ``{2*x|x={-1,2;3,-4};x>0}``, but
``{2*x|x={1,2;3,-4};x>0}`` doesn't because the rows of the result matrix have
different lengths.
マトリクス内包にフィルタを含めると失敗するので注意して下さい。なぜかというと、フィルタした結果はもはや長方形のマトリクスではないからです。例えば ``{2*x|x={1,2,3,-4};x>0}`` はうまくいきます。 ``{2*x|x={-1,2;3,-4};x>0}`` も大丈夫。しかし ``{2*x|x={1,2;3,-4};x>0}`` だとうまくいきません。結果となるマトリクスの行の長さがそれぞれ違ってしまうからです。
As a slightly more comprehensive example (no pun intended!), here is a
definition of matrix multiplication in Pure. The building block here is the
"dot" product of two vectors which can be defined as follows:
もう少しわかりやすい例として(シャレじゃなくて! [#]_ )、 Pure で定義したマトリクス乗算を示します。 The building block here は "dot" 関数による2つのベクターの積ですが、次のように定義できます::
> sum = foldl (+) 0;
> dot x::matrix y::matrix = sum $ zipwith (*) (rowvector x) (rowvector y);
> dot {1,2,3} {1,0,1};
4
.. [#] 訳注: "matrix *comprehension*" (マトリクス内包)の話題で "As a slightly more *comprehensive* example" (もう少しわかりやすい例として)と出ているため、ダジャレ疑惑を否定している。故意ではない表現をシャレと解釈されたくない心境は文化を問わないらしい。
The general matrix product now boils down to a simple matrix comprehension
which just computes the dot product of all rows of ``x`` with all columns of
``y`` (the ``rows`` and ``cols`` functions are prelude operations found in
matrices.pure):
ここでマトリクスの一般的な積をシンプルなマトリクス内包へと煮詰めます。 ``x`` の全行と ``y`` の全列との積を計算するだけでよいのです( ``rows`` 関数と ``cols`` 関数は prelude で定義される演算で、 matrices.pure 内にあります)::
> x::matrix * y::matrix = {dot u v | u = rows x; v = cols y};
> {0,1;1,0;1,1}*{1,2,3;4,5,6};
{4,5,6;1,2,3;5,7,9}
(For the sake of simplicity, this doesn't do much error checking. In
production code you'd check at least the conformance of matrix dimensions, of
course.)
(簡潔にするため、あまりエラーチェックを行っていません。実用するコードでは、少なくともマトリクスの大きさが一致していることをチェックすべきです)
Well, that was easy. So let's take a look at a more challenging example,
Gaussian elimination, which can be used to solve systems of linear
equations. The algorithm brings a matrix into "row echelon" form, a
generalization of triangular matrices. The resulting system can then be solved
quite easily using back substitution.
うん、簡単でした。ではもう少し骨の折れる例として、ガウスの消去法〔Gaussian elimination〕を見てみましょう。線型方程式系(連立一次方程式)を解くのに使われるものです。このアルゴリズムはマトリクスを階段行列〔"row echelon" form〕つまり三角行列を一般化したものへ変形します。その結果として得られる系は後退代入〔back substitution〕を使って簡単に解くことができます。
Here is a Pure implementation of the algorithm. Note that the real meat is in
the pivoting and elimination step (``step`` function) which is iterated over
all columns of the input matrix. In each step, ``x`` is the current matrix,
``i`` the current row index, ``j`` the current column index, and ``p`` keeps
track of the current permutation of the row indices performed during
pivoting. The algorithm returns the updated matrix ``x``, row index ``i`` and
row permutation ``p``.
このアルゴリズムを Pure で実装したものを示します。真の要点はピボッティングと消去ステップ( ``step`` 関数)にあり、入力されたマトリクスの全ての列に対して繰り返し適用され〔=イテレートされ〕ると覚えておいて下さい。各ステップにおいて ``x`` は現在のマトリクスであり、 ``i`` は現在の行インデックス、 ``j`` は現在の列インデックス、 ``p`` は■ピボッティング中に実行される行インデックスの現在の順列■を記録します。このアルゴリズムは更新されたマトリクス ``x`` 、行インデックス ``i`` 、順列 ``p`` を返します。
::
gauss_elimination x::matrix = p,x
when n,m = dim x; p,_,x = foldl step (0..n-1,0,x) (0..m-1) end;
// One pivoting and elimination step in column j of the matrix:
step (p,i,x) j
= if max_x==0 then p,i,x
else
// updated row permutation and index:
// 更新された行順列とインデックス
transp i max_i p, i+1,
{// the top rows of the matrix remain unchanged:
// 最上段の行は変更されないまま:
x!!(0..i-1,0..m-1);
// the pivot row, divided by the pivot element:
// ピボット要素によって分割されたピボット行:
{x!(i,l)/x!(i,j) | l=0..m-1};
// subtract suitable multiples of the pivot row:
// ピボット行の suitable multiples を引く
{x!(k,l)-x!(k,j)*x!(i,l)/x!(i,j) | k=i+1..n-1; l=0..m-1}}
when
n,m = dim x; max_i, max_x = pivot i (col x j);
x = if max_x>0 then swap x i max_i else x;
end with
pivot i x = foldl max (0,0) [j,abs (x!j)|j=i..#x-1];
max (i,x) (j,y) = if x<y then j,y else i,x;
end;
Please refer to any good textbook on numerical mathematics for a closer
description of the algorithm. But here is a brief rundown of what happens in
each elimination step: First we find the pivot element in column ``j`` of the
matrix. (We're doing partial pivoting here, i.e., we only look for the element
with the largest absolute value in column ``j``, starting at row ``i``. That's
usually good enough to achieve numerical stability.) If the pivot is zero then
we're done (the rest of the pivot column is already zeroed out). Otherwise, we
bring it into the pivot position (swapping row ``i`` and the pivot row),
divide the pivot row by the pivot, and subtract suitable multiples of the
pivot row to eliminate the elements of the pivot column in all subsequent
rows. Finally we update ``i`` and ``p`` accordingly and return the result.
このアルゴリズムの詳細な解説は numerical mathematics の良い参考書をあたって下さい。しかし、この例は各消去ステップで起きることの簡潔な要約になっています。まず、マトリクスの ``j`` 列からピボット要素を探します(ここでは部分ピボッティングを行っています。すなわち、 ``j`` 列のうちで最も大きい絶対値を持つ要素だけを、行 ``i`` から順に探します。通常、 numerical stability を保つにはこれで充分です)。もしピボットがゼロならば、完了です(残りのピボット列はすでにゼロとされています)。そうでない場合、 it をピボット位置へ移動し(行 ``i`` とピボット行を置き換える)、ピボット行をピボットで分割し、全後続行内のピボット列から要素を消去するため、適切な倍数をピボット行から引きます。
In order to complete the implementation, we still need the following little
helper functions to swap two rows of a matrix (this is used in the pivoting
step) and to apply a transposition to a permutation (represented as a list):
実装を完了するには、まだ次の小さなヘルパー関数が必要です。この関数はマトリクスの行2つを入れ替え(ピボッティングステップで使われます)、また a transposition を a permutation (represented as a list) に適用するものです::
swap x i j = x!!(transp i j (0..n-1),0..m-1) when n,m = dim x end;
transp i j p = [p!tr k | k=0..#p-1]
with tr k = if k==i then j else if k==j then i else k end;
Finally, let us define a convenient print representation of double matrices a
la Octave_ (the meaning of the ``__show__`` function is explained in the
`Caveats and Notes`_ section):
最後に、便利な print representation of double matrices a la Octave_ を定義しましょう( ``__show__`` 関数の意味は `Caveats and Notes`_ セクションで説明されています)::
using system;
__show__ x::matrix
= strcat [printd j (x!(i,j))|i=0..n-1; j=0..m-1] + "\n"
with printd 0 = sprintf "\n%10.5f"; printd _ = sprintf "%10.5f" end
when n,m = dim x end if dmatrixp x;
Example:
具体例::
> let x = dmatrix {2,1,-1,8; -3,-1,2,-11; -2,1,2,-3};
> x; gauss_elimination x;
2.00000 1.00000 -1.00000 8.00000
-3.00000 -1.00000 2.00000 -11.00000
-2.00000 1.00000 2.00000 -3.00000
[1,2,0],
1.00000 0.33333 -0.66667 3.66667
0.00000 1.00000 0.40000 2.60000
0.00000 0.00000 1.00000 -1.00000
Record Data
-----------
レコード
Matrices also provide a means to represent simple record-like data, by
encoding records as symbolic vectors consisting of "hash pairs" of the form
``key => value``. This kind of data structure is very convenient to represent
aggregates with lots of different components. Since the components of records
can be accessed by indexing with key values, you don't have to remember which
components are stored in which order, just knowing the keys of the required
members is enough. In contrast, tuples, lists and other kinds of constructor
terms quickly become unwieldy for such purposes.
マトリクスはシンプルなレコードのようなデータを提供します。 ``key => value`` という形式の「ハッシュペア」から構成されるシンボリックベクトルとしてレコードをエンコードします。この種のデータ構造は、様々な異なる構成要素からなる集合体を表すのにとても便利です。キーの値をインデックスとしてレコードの要素にアクセスできるので、各要素がどの順番で保存されているか覚えておく必要はなく、必要なメンバーのキーさえわかっていれば充分です。対照的に、タプルやリストなど他の constructor terms はすぐにこうした目的で扱いにくいものとなってしまいます。
.. _Record Functions: purelib.html#record-functions
The keys used for indexing the record data must be either symbols or strings,
while the corresponding values may be arbitrary Pure values. The prelude
provides some operations on these special kinds of matrices, which let you
retrieve vector elements by indexing and perform non-destructive updates, see
the `Record Functions`_ section in the `Pure Library Manual`_ for
details. Here are a few examples which illustrate how to create records and
work with them:
レコードデータの索引となるキーはシンボルか文字列である必要があります。それに対応する値は任意の Pure 値とすることができます。 prelude はこの特殊なマトリクスに対するいくつかの処理を提供します。インデックスによってベクトル要素を取り出したり、非破壊的な更新を行うことが可能となります。詳しくは `Pure Library Manual`_ 内の `Record Functions`_ セクションを参照して下さい。ここでは、レコードの作成と、それを使った作業を解説する例をいくつか示します::
> let r = {x=>5, y=>12};
> recordp r, member r x;
1,1
> r!y; r!![y,x];
12
{12,5}
> insert r (x=>99);
{x=>99,y=>12}
> insert ans (z=>77);
{x=>99,y=>12,z=>77}
> delete ans z;
{x=>99,y=>12}
Note the use of the "hash rocket" ``=>`` which denotes the ``key=>value``
associations in a record. The hash rocket is a constructor declared as an
infix operator in the prelude, see the Prelude_ section in the `Pure Library
Manual`_. There's one caveat here, however. Since neither ``=>`` nor ``!``
treat their key operand in a special way, symbols used as keys must not be
bound to a value (to ensure this, you might want to declare them as
``nonfix``), or you'll have to protect them from being evaluated by quoting
them. Thus, to be on the safe side, you should actually write:
「ハッシュロケット」 ``=>`` が使われている部分に注意を向けて下さい。この記号がレコード内での ``key=>value`` の結びつきを示しています。ハッシュロケットは prelude 内で挿入演算子として定義されているコンストラクタです( `Pure Library Manual`_ 内の Prelude_ セクションを参照)が、一つだけ注意点があります。 ``=>`` も ``!`` も、キーとなるオペランドを特別な方法で扱っているわけではないので、キーとして使われる複数のシンボルを一つの値に束縛してはいけません(このことを確実にするため、あなたは■それら■を ``nonfix`` として宣言したくなるかもしれません)。あるいは、■それらをクォートすることで評価されるのを防ぐ必要があるでしょう。したがって、安全な道を行くのなら、あなたは次のように書くべきです::
> let r = {'x=>5, 'y=>12};
> r!'y; r!!['y,'x];
12
{12,5}
It's also possible to use strings as keys instead, which may actually be more
convenient in some cases:
代わりに文字列をキーとして使うこともできます。実際はこちらのほうが便利なケースも多いかもしれません::
> let r = {"x"=>5, "y"=>12};
> keys r; vals r;
{"x","y"}
{5,12}
> update r "y" (r!"y"+1);
{"x"=>5,"y"=>13}
You can also mix strings and symbols as keys in the same record (but note that
strings and symbols are always distinct, so ``y`` and ``"y"`` are really two
different keys here):
同じレコードに文字列のキーとシンボルのキーを混在させることも可能です(ただし文字列とシンボルは常に区別されるので、 ``y`` と ``"y"`` はまったく異なる2つのキーとなることを忘れないで下さい)::
> insert r (y=>99);
{"x"=>5,"y"=>12,y=>99}
As records are in fact just special kinds of matrices, the standard matrix
operations can be used on record values as well. For instance, the matrix
constructor provides an alternative way to quickly augment a record with a
collection of new ``key=>value`` associations:
実のところ、レコードは単なる特殊なマトリクスにすぎないので、標準的なマトリクス処理をレコード値に対して同様に使うことができます。例えば、マトリクスコンストラクタを ``key=>value`` 結合のまとまりと合わせて使うことで、レコードを素早く記述するもう一つの方法となります::
> let r = {x=>5, y=>12};
> let r = {r, x=>7, z=>3}; r;
{x=>5,y=>12,x=>7,z=>3}
> r!x, r!z;
7,3
> delete r x;
{x=>5,y=>12,z=>3}
> ans!x;
5
As the example shows, this may produce duplicate keys, but these are handled
gracefully; indexing and updates will always work with the *last* association
for a given key in the record. If necessary, you can remove duplicate entries
from a record as follows; this will only keep the last association for each
key:
上の例が示す通り、この方法では重複したキーを作ることも許されますが、重複したキーは上品に扱われます。索引〔=indexing=キーを指定して値を取得すること〕と更新は常に、与えられたキーを持つ結合のうち *最後に作られた* ものに対して動作するのです。もし必要なら、レコードの重複エントリーを次のように削除することができます。これは各キーの最後の結合だけを保存します::
> record r;
{x=>7,y=>12,z=>3}
In fact, the ``record`` operation not only removes duplicates, but also orders
the record entries by keys. This produces a kind of normalized representation
which is useful if you want to compare or combine two record values
irrespective of the ordering of the fields. For instance:
実のところ、 ``record`` 処理は重複を消去するだけでなく、レコードのエントリーをキーによって整列させることもします。これにより一種の正規化された姿が作り出されるので、2つのレコードの値を、フィールドの並び方に関係なく比較・結合したい場合に役立ちます。例えば::
> record {x=>5, y=>12} === record {y=>12, x=>5};
1
The ``record`` function can also be used to construct a normalized record
directly from a list or tuple of hash pairs:
また ``record`` 関数は、リストやタプルのハッシュペアから、正規化されたレコードを直接構築するのにも使えます::
> record [x=>5, x=>7, y=>12];
{x=>7,y=>12}
Other matrix operations such as ``map``, ``foldl``, etc., and matrix
comprehensions can be applied to records just as easily. This enables you to
perform bulk updates of record data in a straightforward way. For instance,
here's how you can define a function ``maprec`` which applies a function to
all values stored in a record:
``map`` や ``foldl`` などなど他のマトリクス処理や、マトリクス内包も簡単にレコードへ適用できます。これにより、レコードのデータを大量に更新する際もわかりやすい方法で実行できます。例えば、次の例では ``maprec`` 関数を定義する方法を示しています。これは、与えられた関数を、レコードに保存されている全ての値に適用します::
> maprec f = map (\(u=>v) -> u=>f v);
> maprec (*2) {x=>5,y=>12};
{x=>10,y=>24}
Another example: The following ``ziprec`` function collects pairs of values
stored under common keys in two records (we also normalize the result here so
that duplicate keys are always removed):
例をもうひとつ。次の ``ziprec`` 関数は、2つのレコードに共通するキーの下に保存されている値のペアを集めてくるものです::
> ziprec x y = record {u=>(x!u,y!u) | u = keys x; member y u};
> ziprec {a=>3,x=>5,y=>12} {x=>10,y=>24,z=>7};
{x=>(5,10),y=>(12,24)}
Thus the full power of generic matrix operations is available for records,
which turns them into a very versatile data structure, much more powerful than
records in conventional programming languages which are usually limited to
constructing records and accessing or modifying their components. Note that
since the values stored in records can be arbitrary Pure values, you can also
have mutable records by making use of Pure's expression references (see
`Expression References`_ in the library manual). And of course records can be
nested, too:
このように、ジェネリックなマトリクス処理のフルパワーをレコードに対して使うことができ、レコードを万能な〔versatile〕データ構造に変えてくれます。従来のプログラミング言語に備わっているレコードは、構築するにも、構成要素に対してアクセスや更新をするにも、しばしば制限があります。Pure のレコードはそれよりはるかに強力です。レコードには任意の Pure 値を保存することができるので、 Pure の式リファレンスを使えば、 mutable なレコードを使うこともできることを忘れないで下さい。もちろんレコードはネストすることもできます::
> let r = {a => {b=>1,c=>2}, b => 2};
> r!a, r!b, r!a!b;
{b=>1,c=>2},2,1
.. _Expression References: purelib.html#expression-references
Macros
======
マクロ
Macros are a special type of functions to be executed as a kind of
"preprocessing stage" at compile time. In Pure these are typically used to
define custom special forms and to perform inlining of function calls and
other simple kinds of source-level optimizations.
マクロは特別なタイプの関数であり、コンパイル時の一種のプリプロセス段階〔"preprocessing stage"〕で実行されます。 Pure においてこれらは典型的に、カスタム特別形を定義するためや、関数呼び出しの直列化〔inlining〕を実行するため、あるいは単純な類のソースレベルでの最適化を行うために使われます。
Whereas the macro facilities of most programming languages simply provide a
kind of textual substitution mechanism, Pure macros operate on symbolic
expressions and are implemented by the same kind of rewriting rules that are
also used to define ordinary functions in Pure. In difference to these, macro
rules start out with the keyword ``def``, and only simple kinds of rules
without any guards or multiple left-hand and right-hand sides are permitted.
ほとんどのプログラミング言語において、マクロは、テキスト的な代替物を提供する仕組みとして便利であるのに対して、 Pure のマクロは記号式の上で作動し、通常の関数を定義する際に使われるのと同じく書き換えルールとして定義されています。通常の書き換えルールと異なるのは、マクロのルールは ``def`` キーワードを先頭に書き始める点と、シンプルなルールだけが許され、ガードや複数の左辺・右辺は許されていないという点です。
Syntactically, a macro definition looks just like a variable or constant
definition, using ``def`` in lieu of ``let`` or ``const``, but they are
processed in a different way. Macros are substituted into the right-hand sides
of function, constant and variable definitions. All macro substitution happens
before constant substitutions and the actual compilation step. Macros can be
defined in terms of other macros (also recursively), and are evaluated using
call by value (i.e., macro calls in macro arguments are expanded before the
macro gets applied to its parameters).
統語的には、マクロ定義は変数や定数の定義とよく似ており、 ``let`` や ``const`` の代わりに ``def`` を使いますが、それぞれが処理される方法は異なります。マクロは右辺にある関数、定数、変数の定義の代わりとなります。全マクロの置換は、定数の置換や実際のコンパイルステップよりも前に実行されます。マクロは他のマクロを使って定義することもできます(再帰的にもできます)。また、値呼び出しで評価されます(つまり、マクロ引数内でのマクロ呼び出しはマクロがパラメータへ適用される前に展開されます)。
Optimization Rules
------------------
最適化ルール
Here is a simple example, showing a rule which expands saturated calls of the
``succ`` function (defined in the prelude) at compile time:
次のシンプルな例は ``succ`` 関数(prelude 内で定義されている)の過剰な呼び出しをコンパイル時に展開するルールを示しています::
> def succ x = x+1;
> foo x::int = succ (succ x);
> show foo
foo x::int = x+1+1;
Rules like these can be useful to help the compiler generate better code. Note
that a macro may have the same name as an ordinary Pure function, which is
essential if you want to optimize calls to an existing function, as in the
previous example. (Just like ordinary functions, the number of parameters in
each rule for a given macro must be the same, but a macro may have a different
number of arguments than the corresponding function.)
このようなルールはコンパイラがより良いコードを生成する助けとなりうるものです。マクロが Pure の一般的な関数と同じ名前を持つことを許されていることを覚えておいて下さい。このことは、(上の例のように)すでに存在する関数の呼び出しを最適化したい場合にきわめて重要です(一般的な関数とちょうど同じように、あるマクロに対するルールそれぞれが取るパラメータの数は同じでなければいけません。しかし、マクロは、対応する関数とは異なる数のパラメータを取ることが許されています)。
A somewhat more practical example is the following rule from the prelude,
which eliminates saturated instances of the right-associative function
application operator:
prelude から取ってきた次の例はいくらか実践的です。この例では、右結合の関数適用演算子の過剰なインスタンスを排除します::
def f $ x = f x;
Like in Haskell, this low-priority operator is handy to write cascading
function calls. With the above macro rule, these will be "inlined" as ordinary
function applications automatically. Example:
Haskell で使うのと同じように、この優先度の低い演算子は、段になって流れ落ちる〔cascading〕関数呼び出しを書くのに便利です。上のマクロルールと合わせると、これらを通常の関数適用と同じようなものとして自動的に「インライン化」できます。具体例::
> foo x = bar $ bar $ 2*x;
> show foo
foo x = bar (bar (2*x));
Here are two slightly more tricky rules from the prelude, which optimize the
case of "throwaway" list comprehensions. This is useful if a list
comprehension is evaluated solely for its side effects:
次は prelude からもう少しトリッキーなルールを2つ。これらはリスト内包を「使い捨て」〔"throwaway"〕するケースを最適化します。副作用を利用したいためだけにリスト内包が評価される場合に役立ちます。
def void (catmap f x) = do f x;
def void (listmap f x) = do f x;
Note that the ``void`` function simply throws away its argument and returns
``()`` instead. The ``do`` function applies a function to every member of a
list (like ``map``), but throws away all intermediate results and just returns
``()``, which is much more efficient if you don't need those results
anyway. These are both defined in the prelude.
``void`` 関数は、与えられた引数を単純に捨て、代わりに ``()`` を返す関数であることを覚えておいて下さい。 ``do`` 関数は、与えられた関数をリストの各メンバーに( ``map`` のように)適用しますが、中途段階で生じる返値をすべて捨て、ただ ``()`` を返します。中途段階の返値が必要ない場合にはとても効率的です。両館数は prelude で定義されます。
Before we delve into this example, a few remarks are in order about the way
list comprehensions are implemented in Pure. As already mentioned, list
comprehensions are just syntactic sugar; the compiler immediately transforms
them to an equivalent expression involving only lambdas and a few other list
operations. Note that list comprehensions are essentially equivalent to piles
of nested lambdas, filters and maps, but for various reasons they are actually
implemented using two special helper operations, ``catmap`` and ``listmap``.
この例を掘り下げる前に、 Pure におけるリスト内包の実装方法について手短に整理しておきましょう。すでに述べた通り、リスト内包は糖衣構文に過ぎません。コンパイラはすぐにそれを、ラムダといくつかのリスト演算で構成される等価な式へ変形します。リスト内包はネストされたラムダ、フィルター、マップを積み重ねたものと本質的に等価であると覚えておいて下さい。しかし様々な理由から、それらは実際には ``catmap`` と ``listmap`` という特別なヘルパー処理を使って実装されています。
The ``catmap`` operation combines ``map`` and ``cat``; this is needed, in
particular, to accumulate the results of nested generators, such as ``[i,j | i
= 1..n; j = 1..m]``. The same operation is also used to implement filter
clauses, you can see this below in the examples. However, for efficiency
simple generators like ``[2*i | i = 1..n]`` are translated to a ``listmap``
instead (which is basically just ``map``, but works with different aggregate
types, so that list comprehensions can draw values from aggregates other than
lists, such as matrices).
``catmap`` 処理は ``map`` と ``cat`` を組み合わせたものです。これは、例えば ``[i,j | i = 1..n; j = 1..m]`` といったように、ネストされたジェネレータの結果を蓄積するために特に必要です。フィルター節の実装も同じ処理を使って実装しています。下の例でその例を見ることができます。しかし、効率化のため、 ``[2*i | i = 1..n]`` のようなシンプルなジェネレータは ``listmap`` へと変換されます(これは単なる ``map`` ですが、異なる型の集合をも扱うことができます。その結果、リスト内包は、マトリクスのようなリスト以外の集合からも値を引き出すことができるのです)。
Now let's see how the rules above transform a list comprehension if we
"voidify" it:
さあ、私たちがリスト内包を "voidfy" したとき、上のルールがどのようにそれを変形するか見てみましょう::
> using system;
> f = [printf "%g\n" (2^x+1) | x=1..5; x mod 2];
> g = void [printf "%g\n" (2^x+1) | x=1..5; x mod 2];
> show f g
f = catmap (\x -> if x mod 2 then [printf "%g\n" (2^x+1)] else []) (1..5);
g = do (\x -> if x mod 2 then [printf "%g\n" (2^x+1)] else []) (1..5);
Ok, so the ``catmap`` got replaced with a ``do`` which is just what we need to
make this code go essentially as fast as a ``for`` loop in conventional
programming languages (up to constant factors, of course). Here's how it looks
like when we run the ``g`` function:
OK、 ``catmap`` が ``do`` に置き換えられました。よくあるプログラミング言語の ``for`` ループと本質的に同じくらいこのコードを速くする(up to constant factors, of course)のに必要なのは、まさにこれなんです。 ``g`` 関数を実行するとこんな風に見えます::
> g;
3
9
33
()
It's not all roses, however, since the above macro rules will only get rid of
the outermost ``catmap`` if the list comprehension binds multiple variables:
It's not all roses, however, なぜならリスト内包が複数の変数を束縛している場合、上のマクロルールは最も外側の ``catmap`` を取り除くだけだからです::
> u = void [puts $ str (x,y) | x=1..2; y=1..3];
> show u
u = do (\x -> listmap (\y -> puts (str (x,y))) (1..3)) (1..2);
If you're bothered by this, you'll have to apply ``void`` recursively,
creating a nested list comprehension which expands to a nested ``do``:
これにお悩みならば、 ``void`` を再帰的に適用すればよいのです。ネストされた ``do`` へと拡大されたリスト内包を作ります::
> v = void [void [puts $ str (x,y) | y=1..3] | x=1..2];
> show v
v = do (\x -> do (\y -> puts (str (x,y))) (1..3)) (1..2);
(It would be nice to have this handled automatically, but the left-hand side
of a macro definition must be a simple expression, and thus it's not possible
to write a macro which descends recursively into the lambda argument of
``catmap``.)
(これが自動的に扱われるととても良いのですが、しかしマクロ定義の左辺はシンプルな式である必要があります。そのため ``catmap`` のラムダ引数へと再帰的に降りていくマクロを書くことはできません)
Recursive Macros
----------------
再帰マクロ
Macros can also be recursive, in which case they usually consist of multiple
rules and make use of pattern-matching like ordinary function definitions. As
a simple example, let's implement a Pure version of Lisp's quasiquote which
allows you to create a quoted expression from a "template" while substituting
variable parts of the template. (For the sake of brevity, our definition is
somewhat simplified and does not cover some corner cases. See the Pure
distribution for a full version of this example.)
マクロは再帰的であることもできます。この場合、マクロは複数のルールで構成されることが多く、通常の関数と同じようにパターンマッチングを使うこともできます。シンプルな例として、 Lisp の準引用〔quasiquote〕を実装してみましょう。準引用は、「テンプレート」からクォートされた式を作り出し、それと同時にテンプレートの変数部分の代わりとなるものです(簡潔にするため、ここでの定義はいくらか単純化してあり、やっかいなケースをカバーしきれない部分があります。この例の完全版は Pure の配布パッケージを参照して下さい)。
::
def quasiquote (unquote x) = x;
def quasiquote (f@_ (splice x)) = foldl ($) (quasiquote f) x;
def quasiquote (f@_ x) = quasiquote f (quasiquote x);
def quasiquote x = quote x;
(Note the ``f@_``, which is an anonymous "as" pattern forcing the compiler to
recognize ``f`` as a function variable, rather than a literal function
symbol. See `Head = Function`_ in the `Caveats and Notes`_ section for an
explanation of this trick.)
( ``f@_`` の部分に注意して下さい。これは匿名の "as" パターンで、コンパイラが ``f`` を、リテラルな関数シンボルではなく function variable と解釈するよう強制します。このトリックの説明は `Caveats and Notes`_ セクション内の `Head = Function`_ を参照して下さい)
The first rule above takes care of "unquoting" embedded subterms. The second
rule "splices" an argument list into an enclosing function application. The
third rule recurses into subterms of a function application, and the fourth
and last rule takes care of quoting the "atomic" subterms. Note that
``unquote`` and ``splice`` themselves are just passive constructor symbols,
the real work is done by ``quasiquote``, using ``foldl`` at runtime to
actually perform the splicing. (Putting off the splicing until runtime makes
it possible to splice argument lists computed at runtime.)
上の例の最初のルールは "unquoting" embedded subterms に配慮したものです。2番目のルールは引数リストを enclosing function application へと "splice" します。3番目のルールは function application の下位項へ再帰します。そして最後となる4番目のルールは "atomic" な下位項をクオートする面倒を見ます。 ``unquote`` と ``splice`` が実のところ消極的なコンストラクタシンボルにすぎないことを覚えておいて下さい。実際の仕事は ``quasiquote`` によって行われます。 ``quasiquote`` は runtime に ``foldl`` を使って splicing を実施します(runtimeまでsplicingをputting off することで、実行時に計算される引数リストをspliceすることが可能になります)。
If we want, we can also add some syntactic sugar for Lisp weenies. (Note that
we cannot have '``,``' for unquoting, so we use '``,$``' instead.)
お望みなら Lisp weenies に糖衣構文を追加することもできます( Pure には unquote 用の '``,``' が存在しないので、代わりに '``$``' を使います)。
::
prefix 9 ` ,$ ,@ ;
def `x = quasiquote x; def ,$x = unquote x; def ,@x = splice x;
Examples:
具体例::
> `(2*42+2^12);
2*42+2^12
> `(2*42+,$(2^12));
2*42+4096.0
> `foo 1 2 (,@'[2/3,3/4]) (5/6);
foo 1 2 (2/3) (3/4) (5/6)
> `foo 1 2 (,@'args) (5/6) when args = '[2/3,3/4] end;
foo 1 2 (2/3) (3/4) (5/6)
We mention in passing here that, technically, Pure macros are just as powerful
as (unconditional) term rewriting systems and thus they are
Turing-complete. This implies that a badly written macro may well send the
Pure compiler into an infinite recursion, which results in a stack overflow at
compile time. See the `Caveats and Notes`_ section for information on how to
deal with these by setting the PURE_STACK environment variable.
ちなみに、技術的に言えば Pure のマクロは (unconditional) term rewriting systemと同じくらい強力であり、したがってチューリング完全です。つまり、ダメなマクロを書いてしまうと Pure コンパイラを無限再帰に陥れることにもなり得ます。この場合、コンパイル中にスタックオーバーフローという結果になります。 PURE_STACK 環境変数を設定してこのエラーを取り扱う方法については `Caveats and Notes`_ セクションを参照して下さい。
User-Defined Special Forms
--------------------------
ユーザ定義の特別形
The ``quasiquote`` macro in the preceding subsection also provides an example
of how you can use macros to define your own special forms. This works because
the actual evaluation of macro arguments is put off until runtime, and thus we
can safely pass them to built-in special forms and other constructs which
defer their evaluation at *runtime*. In fact, the right-hand side of a macro
rule may be an arbitrary Pure expression involving conditional expressions,
lambdas, binding clauses, etc. These are never evaluated during macro
substitution, they just become part of the macro expansion (after substituting
the macro parameters).
前節で示した ``quasiquote`` マクロは、あなた独自の特別形を定義するためにマクロを使う方法の例ともなっています。これが機能するのは、マクロの引数に対する評価が実行時まで遅延されるからです。したがって、私たちはマクロの引数を組み込み特別形や他の構造体へと安全に渡すことができ、which defer their evaluation at *runtime*. 実際、マクロルールの右辺は任意の Pure 式であり、条件式、ラムダ、束縛節〔binding clauses〕等々もここに含まれます。これらはマクロの代入まで決して評価されることはなく、単にマクロ展開の一部となります(マクロのパラメータを代入した後に)。
Here is another useful example of a user-defined special form, the macro
``timex`` which employs the system function ``clock`` to report the cpu time
in seconds needed to evaluate a given expression, along with the computed
result:
ここで、ユーザ定義特別形の便利な例をもう一つ示します。 ``timex`` マクロは、システム関数 ``clock`` を使い、与えられた式の評価に必要な CPU タイム(秒)を、計算された結果に沿ってレポートします::
> using system;
> def timex x = (clock-t0)/CLOCKS_PER_SEC,y when t0 = clock; y = x end;
> sum = foldl (+) 0L;
> timex $ sum (1L..100000L);
0.43,5000050000L
Note that the above definition of ``timex`` wouldn't work as an ordinary
function definition, since by virtue of Pure's basic eager evaluation strategy
the ``x`` parameter would have been evaluated already before it is passed to
``timex``, making ``timex`` always return a zero time value. Try it!
上の定義では ``timex`` の定義が通常の関数定義として機能しないことに注意して下さい。 Pure の基本的な先行評価ストラテジーの美徳により、 ``x`` パラメータが ``timex`` に渡される前に評価されることはなく、 ``timex`` は常にゼロ時間の値を返します。試してみて!
Here's yet another example, which is handy if you need to trace function
calls. (As of Pure 0.22, the interpreter now has its own built-in debugging
facility, see Debugging_. However, the following macro allows you to trace
functions using your own custom output format, and may thus be useful in
situations where the built-in debugger is not appropriate.)
ここでもう一つ例を。 trace function calls が必要な場合に便利なものです(Pure 0.22 現在、インタープリタは組み込みのデバッグ機能を持つに至っています。 Debugging_ を参照して下さい。しかし、次のマクロを使えば、あなた独自の出力フォーマットを使って関数をトレースすることができるようになります。組み込みデバッガではうまくいかない場面で役に立つかもしれません)。
::
using system;
def trace f x y = printf "** exit %s: %s -> %s\n" (str f,str x,str y) $$ y
when y = printf "** call %s: %s\n: " (str f,str x) $$ gets $$ y end;
This macro is invoked with the function to be traced, the arguments (or
whatever you want to be printed as additional debugging information) and the
actual function call as parameters. (This is a rather simplistic version,
which just prints a prompt on function entry and the final reduction after the
call. You can easily make this as elaborate as you like. E.g., you might want
to keep track of recursive levels and profiling information, add various
interactive commands to selectively enable and disable tracing during the
evaluation, etc.)
このマクロはトレースされる関数、引数(または、あなたが表示したい追加デバッグ情報)、パラメータとなる実際の関数呼び出しを引数として呼び出されます(これはシンプル版であり、関数へのエントリー時にプロンプトを表示し、関数呼び出しの後で the final reduction を表示するだけです。あなたが望むだけ精密なものを作るのも簡単です。例えば、あなたは再帰の深さとプロファイリング情報を記録したいと思ったり、様々な対話型コマンドを追加して、評価中にトレース動作の有効・無効を切り替えられるようにしたいと思うこともあるでしょう)。
We can still make this a bit more convenient by introducing the following
ordinary function definition:
次の通常の関数定義を導入して、これをもう少しだけ便利にすることもできます::
trace f x = trace f x (f x);
This lets us patch up a call to trace a given function, as shown below,
without having to change the definition of the function at all. This trick
only works with global functions; for local functions you'll have to add an
explicit call of the ``trace`` macro to the local definition yourself. Also
note that the definition above only works with functions taking a single
parameter; see the trace.pure example in the distribution for the full version
which can deal with any number of arguments.
こうすることで、次に示す通り、与えられた関数をトレースするために呼び出しを patch up することができます。関数定義に手を加える必要はありません。このトリックはグローバル変数に対してのみ動作します。ローカル変数をトレースするためには、明確な ``trace`` マクロ呼び出しをローカル定義に追加してやる必要があります。また、上の定義が機能するのはパラメータを1つ取る関数に対してだけであることにも注意して下さい。配布パッケージ内の trace.pure の例には、あらゆる数の引数を扱える完全版がありますので、参照して下さい。
::
// Uncomment this line to trace calls to the 'fact' function.
def fact n = trace fact n;
// Sample function to be traced.
fact n = if n>0 then n*fact(n-1) else 1;
Here's a trace of the ``fact`` function obtained in this fashion (hit carriage
return after each '``:``' prompt to proceed with the computation):
この方法で取得した ``trace`` 関数のトレースをここで示します( '``:``' プロンプトが表示されたら、計算を進めるためにリターンキーを押して下さい)::
> fact 2;
** call fact: 2
:
** call fact: 1
:
** call fact: 0
:
** exit fact: 0 -> 1
** exit fact: 1 -> 1
** exit fact: 2 -> 2
2
Note that by just removing the macro definition for ``fact`` above, you can
make the function run untraced as usual again. This scheme is quite flexible,
the only real drawback is that you have to explicitly add some code for each
function you want to trace.
``fact`` のためのマクロ定義をただ除去するだけで、トレースを行わず普段通りの状態で再び関数を実行させることができるようになります。このスキームはとてもフレキシブルですが、ただ一つ本当に難点なのは、トレースしたいと思う関数に対していくらかのコードを明確に追加しなければならないところです。
Macro Hygiene
-------------
マクロの衛生学
Pure macros are lexically scoped, i.e., the binding of symbols in the
right-hand-side of a macro definition is determined statically by the text of
the definition, and macro parameter substitution also takes into account
binding constructs, such as ``with`` and ``when`` clauses, in the right-hand
side of the definition. Macro facilities with these pleasant properties are
also known as `hygienic macros`. They are not susceptible to so-called "name
capture," which makes macros in less sophisticated languages bug-ridden and
hard to use. (This is explained in more detail in the `Hygienic Macros`_
section.)
Pure のマクロはレキシカルスコープです。すなわち、マクロ定義の右辺にあるシンボルの束縛は定義のテキストによって静的に決定されます。そしてマクロパラメータの代入もまた、定義右辺にある束縛構造( ``with`` や ``when`` 節など)を考慮に入れます。これら pleasant properties によるマクロのfacilitiesは `hygienic macros` としても知られています。Theyは、いわゆる "name capture" に感染することがありません。 "name capture" は、あまり洗練されていない言語のマクロを、バグを含みやすく、扱いづらいものにします( `Hygienic Macros`_ セクションではもっと細かく説明しています)。
Pure macros also have their limitations. Specifically, the left-hand side of a
macro rule must be a simple expression, just like in ordinary function
definitions. This restricts the kinds of expressions which can be rewritten by
a macro. But Pure macros are certainly powerful enough for most common
preprocessing purposes, while still being robust and easy to use.
Pure のマクロもその制限を持っています。特に、通常の関数定義と同じく、マクロルールの左辺はシンプルな式でなければなりません。このことにより、マクロが書き換えることのできる式の種類は限定されます。しかしそれでも Pure のマクロは普通の処理を書くために充分に強力であり、しかも強靱で使いやすいものです。
Declarations
============
宣言
Pure is a very terse language by design. Usually you don't declare much stuff,
you just define it and be done with it. However, there are a few toplevel
constructs which let you declare symbols with special attributes and manage
programs consisting of several source modules:
Pure は設計から非常に簡潔な言語です。たいてい、たくさんの宣言を行うことはなく、ただ宣言してそれを使うだけです。しかし、あなたが特別な属性を持つシンボルを宣言することを許し、複数のソースモジュールから構成されるプログラムを管理する、いくつかのトップレベル構造があります。
* symbol declarations determine "scope" and "fixity" of a symbol;
* シンボル宣言はシンボルの「スコープ」と "fixity" を決定します。
* ``extern`` declarations specify external C functions (described in the
`C Interface`_ section);
* ``extern`` 宣言は外部C関数を定義します(`C Interface`_ セクションを参照)。
* ``using`` clauses let you include other scripts in a Pure script;
* ``using`` 節で、ある Pure スクリプト内から別のスクリプトをインクルードできます。
* ``namespace`` declarations let you avoid name clashes and thereby make it
easier to manage large programs consisting of many separate modules.
* ``namespace`` 宣言により名前の衝突を避けることができ、これによってたくさんのモジュールからなる大きなプログラムを容易に管理できます。
Symbol Declarations
-------------------
シンボル宣言
Scope declarations take the following form:
スコープ宣言は次のような形式をとります::
public symbol ...;
private symbol ...;
This declares the listed symbols as public or private, respectively. Each
symbol must either be an identifier or a sequence of punctuation characters.
The latter kind of symbols *must* always be declared before use, whereas
ordinary identifiers can be used without a prior declaration in which case
they are declared implicitly and default to public scope, meaning that they
are visible everywhere in a program. An explicit public declaration of
ordinary identifiers is thus rarely needed (unless you want to declare symbols
as members of a specific namespace, see `Namespaces`_ below). Symbols can also
be declared private, meaning that the symbol is visible only in the namespace
it belongs to. This is explained in more detail under `Private Symbols`_ in
the Namespaces_ section below.
これはリストされたシンボルを public または private なものとしてそれぞれ宣言しています。各シンボルは、識別子であるか、ひとつながりの句読点文字である必要があります。後者は使用前に *必ず* 宣言されなければ *なりません* 。それに対して、普通の識別子は前もって宣言する必要はなく、その場合は暗黙のうちに宣言され、デフォルトで public スコープとなり、プログラム内のどこからでも見えるものとなります。そのため、通常の識別子を明示的に public 宣言する必要はほとんどありません(特定の名前空間のメンバーとして変数を宣言したい場合は別です。下部 `Namespaces`_ を参照して下さい)。また、シンボルを private として宣言することもできます。このシンボルは属する名前空間の中からしか見えません。これに関して下部 Namespaces_ セクション内 `Private Symbols`_ で詳細に説明されています。
Note that to declare several symbols in a single declaration, you can list
them all with whitespace in between. The same syntax applies to the other
types of symbol declarations discussed below. (Commas are *not* allowed as
delimiters here, as they may occur as legal symbol constituents in the list of
symbols.) The ``public`` and ``private`` keywords can also be used as a prefix
in any of the special symbol declarations discussed below, to specify the
scope of the declared symbols (if the scope prefix is omitted, it defaults to
``public``).
ホワイトスペースを間に入れてシンボルを並べると、一つの宣言文内で複数のシンボルを宣言できることを覚えておいて下さい。同じ文法は、以下で議論される別種のシンボル宣言にも適用されます(ここでカンマは区切り文字として許され *ません* 。シンボルを構成する合法な要素としてカンマがシンボルリスト内に表れる可能性があるからです)。また ``public`` と ``private`` キーワードは、以下で議論される特別シンボル宣言のプレフィクスとして使うこともでき、宣言されるシンボルのスコープを決定します(スコーププレフィクスが省略された場合は ``public`` がデフォルトとなります)。
The following "fixity" declarations are available for introducing special
operator and constant symbols. This changes the way that these symbols are
parsed and thus provides you with a limited means to extend the Pure language
at the lexical and syntactical level.
次の "fixity" 宣言は、特別な演算子シンボルや定数シンボルを導入するためのものです。これはシンボルが解析される方法を変え、 Pure 言語をlexicalおよびsyntacticalなレベルにおいて拡張するための限定された手段を提供します。
Operator declarations: ``infix level symbol ...;``
Pure provides you with a theoretically unlimited number of different
precedence levels for user-defined infix, prefix and postfix operators.
Precedence levels are numbered starting at 0; larger numbers indicate
higher precedence. (For practical reasons, the current implementation does
require that precedence numbers can be encoded as 24 bit unsigned machine
integers, giving you a range from 0 to 16777215, but this should be large
enough to incur no real limitations on applications. Also, the operator
declarations in the prelude have been set up to leave enough "space"
between the "standard" levels so that you can easily sneak in new operator
symbols at low, high or intermediate precedences.)
演算子宣言: ``infix level symbol ...;``
Pure は理論的には無数の異なる優先レベルを、挿入・前置・後置演算子に対して提供します。優先レベルは 0 から始まり、大きい数値ほど優先度が高いことを示します(実用上の理由から、現在の実装では優先度の数値は 24 ビット符号なし machine integer でエンコードされ、 0 から 16777215 までの範囲を使うことができます。しかしアプリケーションにおいて事実上制限なく使えるほどの大きさではあるでしょう。また、 prelude における演算子宣言は「標準」レベル同士の間に十分な「余地」を残して行われます。そのため、優先度が低・高・中間のどのレベルにおいても新しい演算子を〔「標準」演算子の隙間に〕簡単にすべり込ませることができます)。
On each precedence level, you can declare (in order of increasing
precedence) ``infix`` (binary non-associative), ``infixl`` (binary
left-associative), ``infixr`` (binary right-associative), ``prefix``
(unary prefix) and ``postfix`` (unary postfix) operators. For instance,
here is a typical excerpt from the prelude (the full table can be found in
the Prelude_ section of the `Pure Library Manual`_):
各優先レベルにおいて、あなたは(優先度昇順に) ``infix`` (二項、結合なし)、 ``infixl`` (二項、左結合)、 ``infixr`` (二項、右結合)、 ``prefix`` (一項、前置)、 ``postfix`` (一項、後置) 演算子を宣言できます。例えば、これは prelude から抜粋した典型的な例です(完全なテーブルは `Pure Library Manual`_ の Prelude_ セクションにあります)::
infix 1700 < > <= >= == ~= ;
infixl 2100 + - ;
infixl 2200 * / div mod ;
infixr 2400 ^ ;
prefix 2500 # ;
.. _Prelude: purelib.html#prelude
Instead of denoting the precedence by an explicit integer value, you can
also specify an existing operator symbol enclosed in parentheses. Thus the
following declaration gives the ``++`` operator the same precedence as
``+``:
整数で優先度を明示する代わりに、すでに存在する演算子シンボルを丸括弧で囲ったものを指定に使うこともできます。したがって次の宣言では、 ``++`` 演算子に ``+`` と同じ優先度を与えています::
infixl (+) ++ ;
The given symbol may be of a different fixity than the declaration, but it
must have a proper precedence level (i.e., it must be an infix, prefix or
postfix symbol). E.g., the following declaration gives ``^^`` the same
precedence level as the infix ``^`` symbol, but turns it into a postfix
operator:
与えられたシンボルが宣言と異なる fixity となることも可能ですが、しかしそれでも適切な優先度レベル〔a proper precedence level〕を持たなければなりません(つまり infix か prefix か postfix のどれかでなければなりません)。例えば、次の宣言では ``^^`` に挿入演算子シンボル ``^`` と同じ優先度を与えていますが、 ``^^`` を後置演算子に変えています::
postfix (^) ^^ ;
Outfix symbol declarations: ``outfix left right ...;``
Pure also provides unary outfix operators, which work like in Wm Leler's
constraint programming language Bertrand_. Outfix operators let you define
your own bracket structures. The operators must be given as pairs of
matching left and right symbols (which must be distinct). For instance:
アウトフィクスシンボル宣言: ``outfix left right ...;``
Pure は単項のアウトフィクス演算子〔unary outfix operators〕を定義する機能も提供します。これは Wm Leler のconstraint programming language Bertrand_ に似た動作を行います。あなたはアウトフィクス演算子を使って独自のブラケット構造を定義できます。演算子は、左右対応する記号のペア(それぞれ別の記号でなければならない)として与えられる必要があります。例えば::
outfix |: :| BEGIN END;
After this declaration you can write bracketed expressions like ``|:x:|``
or ``BEGIN foo, bar END``. These are always at the highest precedence
level (i.e., syntactically they work like parenthesized expressions). Just
like other operators, you can turn outfix symbols into ordinary functions
by enclosing them in parentheses, but you have to specify the symbols in
matching pairs, such as ``(BEGIN END)``.
この宣言の後、あなたは ``|:x:|`` や ``BEGIN foo, bar END`` のように括弧型の演算子を書くことができます。これらは常に最高の優先レベルとなります(すなわち、統語的には丸括弧で囲われた式のように動作します)。他の演算子と同じように、アウトフィクス演算子を丸括弧で囲うと、それを通常の関数へと変えることができますが、このときのシンボルは ``(BEGIN END)`` のようにペアを対応させて書かなければいけません。
Constant symbol declarations: ``nonfix symbol ...;``
Pure also has a notation for "nullary" operators, i.e., "operators without
operands", which are used to denote special constants. These are
introduced using a ``nonfix`` declaration, e.g.:
定数シンボル宣言: ``nonfix symbol ...;``
Pure はまた「無項」演算子〔"nullary" operators〕を持っています。すなわち「オペランドのない演算子」であり、特別な定数を表すのに使われます。これらは ``nonfix`` 宣言を使って導入されます。例えば::
nonfix red green blue;
Syntactically, these work just like ordinary identifiers, so they may
stand whereever an identifier is allowed (no parentheses are required to
"escape" them). The difference to ordinary identifiers is that nonfix
symbols are always interpreted as literals, even if they occur in a
variable position on the left-hand side of a rule. So, with the above
declaration, you can write something like:
統語上は、これらは通常の演算子と同じように動作します。なので、通常の識別子を置ける場所ならどこにでも置けます(「エスケープ」するのに丸括弧は必要ありません)。通常の識別子との違いは、ノンフィクスシンボルが常にリテラルとして解釈され、たとえルール左辺の変数の位置に表れてもそう解釈されるという点です。なので、上の宣言を行うとこんな風に書けます::
> foo x = case x of red = green; green = blue; blue = red end;
> map foo [red,green,blue];
[green,blue,red]
Thus nonfix symbols are pretty much like nullary constructor symbols in
languages like Haskell. Non-fixity is just a syntactic attribute,
however. Pure doesn't enforce that such values are really "constant", so
you can still write a "constructor equation" like the following:
したがってノンフィクスシンボルは、 Haskell のような言語における無項コンストラクタシンボルとかなり似たものです。しかし Non-fixity は単に統語上の属性です。 Pure はそうした値が本当に "constant" なものであることを強制しません。なので、あなたはまだ "constructor equation" を次のように書くことができます::
> red = blue;
> map foo [red,green,blue];
[blue,blue,blue]
Examples for all types of symbol declarations can be found in the prelude
which declares a bunch of standard (arithmetic, relational, logical) operator
symbols as well as the list and pair constructors '``:``' and '``,``', and a
few nonfix symbols (mostly for denoting different kinds of exceptions).
全タイプのシンボル宣言の例を prelude 内で見つけることができます。 prelude では一連の標準(算術/関係/論理)演算子や、リストコンストラクタ '``:``' 、 ペアコンストラクタ '``,``' 、さらにいくつかのノンフィクスシンボルが(たいていは異なる種類の例外を示すために)定義されています。
One final thing worth noting here is that unary minus plays a special role in
the syntax. Like in Haskell and following mathematical tradition, unary minus
is the only prefix operator symbol which is also used as an infix operator,
and is always on the same precedence level as binary minus, whose precedence
may be chosen freely in the prelude. (The minus operator is the only symbol
which gets that special treatment; all other operators must have distinct
lexical representations.) Thus, with the standard prelude, ``-x+y`` will be
parsed as ``(-x)+y``, whereas ``-x*y`` is the same as ``-(x*y)``. Also note
that the notation ``(-)`` always denotes the binary minus operator; the unary
minus operation can be denoted using the built-in ``neg`` function.
ここに書いておくべき最後の一つは、単項のマイナスが文法上持つ特別な意味についてです。 Haskell と同じように、また数学の伝統を踏襲して、単項のマイナスは挿入演算子としても使われる唯一の前置演算子であり、二項のマイナスと常に同じ優先レベルとなります。二項マイナス演算子の優先度は prelude 内で自由に選ぶことができます(この特別扱いを受けるのはマイナス演算子だけです。他の全演算子は異なるlexical representationsを持たなければなりません)。したがって、標準 prelude を使う場合、 ``-x+y`` は ``(-x)+y`` として解析されます。それに対して ``-x*y`` は ``-(x*y)`` と同じです。また ``(-)`` が常に二項演算子を表すことも覚えておいて下さい。単項マイナス演算は組み込み関数 ``neg`` を使って表すことができます。
Modules and Imports
-------------------
モジュールとインポート
While Pure doesn't offer separate compilation, the ``using`` declaration
provides a simple but effective way to assemble a Pure program from several
source modules. It takes the following form (note that in contrast to symbol
declarations, the comma is used as a delimiter symbol here):
Pure は分割コンパイルを提供していませんが、 ``using`` 宣言は複数のソースモジュールを一つのプログラムへまとめ上げるシンプルかつ効果的な方法を提供します。 ``using`` 宣言は次のような形式をとります(シンボル宣言とは対照的に、ここではカンマを区切り文字として使うことに注意して下さい)::
using name, ...;
This causes each given script to be included in the Pure program at the given
point (if it wasn't already included before), which makes available all the
definitions of the included script in your program. Note that each included
script is loaded only *once*, when the first ``using`` clause for the script
is encountered. Nested imports are allowed, i.e., an imported module may
itself import other modules, etc. A Pure program then basically is the
concatenation of all the source modules given as command line arguments, with
other modules listed in ``using`` clauses inserted at the corresponding source
locations.
この節は、与えられた各スクリプトを、そのプログラムの宣言が置かれた位置にインクルードします(その前ですでに組み込まれていない場合)。これにより、インクルードされたスクリプトの全定義をあなたのプログラム内で使用できるようになります。インクルードされる各スクリプトは、そのスクリプトが指定された ``using`` 節が初めて現れたときの *一度だけ* しか読み込まれない [#]_ ことを忘れないで下さい。ネストされたインポートを使うこともできます。すなわち、インポートされたモジュールが内部で別のモジュールをインポートすることなどが可能です。そして Pure プログラムは基本的に、コマンドライン引数で与えられたソースモジュールがすべて連結され、 ``using`` 節にリストされた他のモジュールがソース内の指定された位置に挿入されたもの、ということになります。
.. [#] 訳注:同じスクリプトを複数回 using しようとしても、読み込まれるのは最初の一度だけ。
(The ``using`` clause also has an alternative form which allows dynamic
libraries to be loaded, this will be discussed in the `C Interface`_ section.)
( ``using`` 節は、動的ライブラリを読み込むための形式も持っています。これについては `C Interface`_ セクションで詳しく議論されています)
For instance, the following declaration causes the math.pure script from the
standard library to be included in your program:
例えば、次の宣言節は math.pure スクリプトを標準ライブラリからあなたのスクリプトへインクルードします::
using math;
You can also import multiple scripts in one go:
一度に複数のモジュールスクリプトをインポートすることもできます::
using array, dict, set;
Moreover, Pure provides a notation for qualified module names which can be
used to denote scripts located in specific package directories, e.g.:
さらに、 Pure は修飾されたモジュール名を指定する機能も提供しています。これは、特定のパッケージディレクトリ内に置かれたスクリプトを指定するために使うものです。例えば::
using examples::libor::bits;
In fact this is equivalent to the following ``using`` clause which spells out
the real filename of the script between double quotes (the ``.pure`` suffix
can also be omitted in which case it is added automatically):
実のところ、この指定は次の ``using`` 節と等価です。次の ``using`` 節では、ダブルクォートの間に実際のスクリプトファイル名を正確に書き記しています( ``.pure`` サフィックスは省略することができます。省略時は自動的に付加されます)::
using "examples/libor/bits.pure";
Both notations can be used interchangeably; the former is usually more
convenient, but the latter allows you to denote scripts whose names aren't
valid Pure identifiers.
両記法の間には互換性があります。普段使うには前者のほうが便利ですが、後者の場合は、有効な Pure 識別子ではない名前 [#]_ を持っているスクリプトを指定することができます。
.. [#] ".pure" で終わっていないファイル名ということだろう。
Script identifiers are translated to the corresponding filenames by replacing
the '``::``' symbol with the pathname separator '``/``' and tacking on the
'``.pure``' suffix. The following table illustrates this with a few examples.
スクリプト識別子は、それに対応するファイル名へと変換されます。その際は '``::``' 記号をパスセパレータ '``/``' に置換し、末尾に '``.pure``' サフィックスを付加します。次の表でいくつかの例を示します。
=========================== ===============================
Script identifier Filename
=========================== ===============================
``math`` ``"math.pure"``
``examples::libor::bits`` ``"examples/libor/bits.pure"``
``::pure::examples::hello`` ``"/pure/examples/hello.pure"``
=========================== ===============================
Note the last example, which shows how an absolute pathname can be denoted
using a qualifier starting with '``::``'.
最後の例では、 '``::``' から始まる修飾子を使って絶対パス名を指定する方法を示しています。
Unless an absolute pathname is given, the interpreter performs a search to
locate the script. The search algorithm considers the following directories in
the given order:
絶対パス名が指定された場合を除き、インタープリタはスクリプトが置かれている位置で検索を行います。検索アルゴリズムは次のディレクトリを、以下に並ぶ順に考慮します:
* the directory of the current script, which is the directory of the script
containing the ``using`` clause, or the current working directory if the
clause was read from standard input (as is the case, e.g., in an interactive
session);
* 現在のスクリプトがあるディレクトリ。これには ``using`` 節で指定されたディレクトリを含む。 ``using`` 節が標準入力から読み込まれた場合にはカレントワーキングディレクトリを含む(as is the case, 例えば対話セッションにおいて)。
* the directories named in -I options on the command line (in the given
order);
* コマンドラインの -I オプションで指定されたディレクトリ(与えられた順に検索)。
* the colon-separated list of directories in the PURE_INCLUDE environment
variable (in the given order);
* 環境変数 PURE_INCLUDE 内で指定された、コロン区切りのディレクトリリスト(与えられた順に検索)。
* finally the directory named by the PURELIB environment variable.
* 最後に、環境変数 PURELIB で指定されたディレクトリ。
Note that the current working directory is not searched by default (unless the
``using`` clause is read from standard input), but of course you can force
this by adding the option -I. to the command line, or by including '.' in the
PURE_INCLUDE variable.
カレントワーキングディレクトリはデフォルトでは検索されないことに注意して下さい(ただし ``using`` 節が標準入力から読まれた場合は別)。しかし -I. オプションをコマンドラインで指定した場合は、もちろん検索を強制することができます。
The directory of the current script (the first item above) can be skipped by
specifying the script to be loaded as a filename in double quotes, prefixed
with the special ``sys:`` tag. The search then starts with the "system"
directories (-I, PURE_INCLUDE and PURELIB) instead. This is useful, e.g., if
you want to provide your own custom version of a standard library script which
in turn imports that library script. For instance, a custom version of
math.pure might employ the following ``using`` clause to load the math.pure
script from the Pure library:
カレントスクリプトのディレクトリ(上のリストの最初のもの)読み込みをスキップすることも可能です。そのスクリプトのファイル名に特別タグ ``sys:`` をプレフィクスとして付加し、ダブルクォートで囲って指定するようにします。すると、検索が "system" ディレクトリ( -I 、 PURE_INCLUDE 、 PURELIB )から開始されます。この動作は、例えば、あなたが独自カスタム版の標準ライブラリスクリプトを提供したいと思い、そのライブラリ内で標準ライブラリスクリプトをインポートしたい場合に便利です。具体例として、カスタム版の math.pure は次の ``using`` 節を使い、 Pure ライブラリから math.pure を読み込みます::
using "sys:math";
// custom definitions go here
log2 x = ln x/ln 2;
The interpreter compares script names (to determine whether two scripts are
actually the same) by using the *canonicalized* full pathname of the script,
following symbolic links to the destination file (albeit only one level). Thus
different scripts with the same basename, such as foo/utils.pure and
bar/utils.pure can both be included in the same program (unless they link to
the same file).
インタープリタはスクリプト名を(2つのスクリプトがまったく同じかどうか判断するため)比較します。その際は、シンボリックリンクを追って(ただし1段階のみ)対象ファイル名を探し、スクリプトの *正規化された* フルパス名〔canonicalized full pathname of the script〕を使って判断します。したがって、同じbasenameを持った異なるスクリプト(例えば foo/utils.pure と bar/utils.pure )の両者を、同じプログラムにインクルードすることができます(両者が同じファイルへとリンクされていれば別です)。
More precisely, canonicalizing a pathname involves the following steps:
もっと正確に言うと、パス名を正規化する過程は以下のステップを含んでいます:
* relative pathnames are expanded to absolute ones, using the search rules
discussed above;
* 相対パスを絶対パスへ展開する。その際は上で議論したルールが使われる。
* the directory part of the pathname is normalized to the form returned by the
``getcwd`` system call;
* パス名の一部となるディレクトリは ``getcwd`` システムコールが返す形式へと正規化される。
* the ".pure" suffix is added if needed;
* 必要ならば ".pure" サフィックスが付加される。
* if the resulting script name is actually a symbolic link, the interpreter
follows that link to its destination, albeit only one level. (This is only
done on Unix-like systems.)
* 結果として得られたスクリプト名がシンボリックリンクであれば、インタープリタはそのリンクを追って対象ファイル名を得る。ただし1段階しか追わない。(これは Unix-like なシステムでのみ行われる)
The directory of the canonicalized pathname is also used when searching other
scripts included in a script. This makes it possible to have an executable
script with a shebang line in its own directory, which is then executed via a
symbolic link placed on the system PATH. In this case the script search
performed in ``using`` clauses will use the real script directory and thus
other required scripts can be located there. This is the recommended practice
for installing standalone Pure applications in source form which are to be run
directly from the shell.
正規化されたパス名のディレクトリは、あるスクリプト内でインクルードされる他のスクリプトを検索する際にも使われます。これにより、 shebang 行を持つ実行可能なスクリプトを its own directory に置いておき、システムの PATH に置かれたシンボリックリンクを通じてそのファイルを実行することも可能になります。この場合、 ``using`` 節で行われるスクリプト検索は実際にスクリプトが置かれているディレクトリを使うようになり、したがって必要な他のスクリプトも同じ場所に置くことができます。これは、ソースのままシェルから実行されるスタンドアローンの Pure アプリケーションをインストールする場合に推奨されるプラクティスです。
Namespaces
----------
名前空間
To facilitate modular development, Pure also provides namespaces as a means to
avoid name clashes between symbols, and to keep the global namespace tidy and
clean. Namespaces serve as containers holding groups of related identifiers
and other symbols. Inside each namespace, symbols must be unique, but the same
symbol may be used to denote different objects (variables, functions, etc.) in
different namespaces. (Pure's namespace system was heavily inspired by C++ and
works in a very similar fashion. So if you know C++ you should feel right at
home and skimming this section to pick up Pure's syntax of the namespace
constructs should be enough to start using it.)
モジュールを使った開発を容易にするため、 Pure は名前空間を提供し、シンボル同士の名前衝突を避け、グローバル名前空間を整頓されていて汚れもない状態に保つ手段としています。名前空間は、関連する識別子や他のシンボルのグループを保持するコンテナとして働きます。各名前空間内では、シンボルは一意でなければなりませんが、名前空間が異なれば、同じシンボルで異なるオブジェクト(変数や関数など)を指し示すことが可能です( Pure の名前空間システムは C++ から非常に強く影響を受けており、かなり同じように動作します。なので、あなたが C++ を知っているなら、ここではリラックスして、このセクションを軽く眺めながら Pure の名前空間構造の文法を拾い読みするだけで、充分使い始めることができるでしょう)。
The global namespace is always available. By default, new symbols are created
in this namespace, which is also called the `default namespace`. Additional
namespaces can be created with the ``namespace`` declaration, which also
switches to the given namespace (makes it the *current* namespace), so that
new symbols are then created in that namespace rather than the default
one. The current namespace also applies to all kinds of symbol declarations,
including operator and constant symbol declarations, as well as ``extern``
declarations (the latter are described in the `C Interface`_ section).
グローバル名前空間は常に利用可能です。デフォルトでは、新しいシンボルはこの名前空間の中に作られます。この名前空間は別名 `default namespace` とも呼ばれます。追加の名前空間は ``namespace`` 宣言で作ることができます。このとき与えられた名前空間への変更が行われ(それを *カレント* 名前空間として)、以後作られる新しいシンボルはその名前空間内に作られることとなり、デフォルト名前空間内ではなくなります。カレント名前空間は全種類のシンボル宣言に対して適用されます。演算子シンボルや定数シンボルの宣言だけでなく、 ``extern`` 宣言も含まれます( extern 宣言は `C Interface`_ セクションに説明があります)。
The basic form of the ``namespace`` declaration has the following syntax
(there's also a "scoped" form of the ``namespace`` declaration which will be
discussed in `Scoped Namespaces`_ at the end of this section):
``namespace`` 宣言の基本的な形式は次のような文法を持っています( "scoped" な形式の ``namespace`` 宣言もありますが、それについてはこのセクションの最後 `Scoped Namespaces`_ で議論されます)::
namespace name;
// declarations and definitions in namespace 'name'
// 'name' 名前空間内での宣言と定義
namespace;
The second form switches back to the default namespace. For instance, in order
to define two symbols with the same print name ``foo`` in two different
namespaces ``foo`` and ``bar``, you can write:
2番目の形式では、デフォルト名前空間へ復帰しています。例えば、同じ ``foo`` という名前を持つシンボル2つを、異なる名前空間 ``foo`` と ``bar`` で宣言するには、次のように書けます::
namespace foo;
foo x = x+1;
namespace bar;
foo x = x-1;
namespace;
We can now refer to the symbols we just defined using `qualified symbols` of
the form ``namespace::symbol``:
``namespace::symbol`` という形式をもつ `修飾子つきシンボル` を使って、今まさに宣言を行いましたが、これで私たちはこれらのシンボルを参照できます::
> foo::foo 99;
100
> bar::foo 99;
98
This avoids any potential name clashes, since the qualified identifier
notation always makes it clear which namespace the given identifier belongs
to.
これにより、あらゆる潜在的な名前衝突を避けられます。修飾子つき識別子の記法により、与えられた識別子がどの名前空間に属すのか、常に明確になるわけです。
A namespace can be "reopened" at any time to add new symbols and definitions
to it. This allows namespaces to be created that span several source
modules. You can also create several different namespaces in the same module.
名前空間はいつでも「再開」して新しいシンボルや定義を追加することができます。なので、名前空間は複数のソースモジュールをまたいで作ることができます。また、一つのモジュールに複数の異なる名前空間を作ることも可能です。
Similar to the ``using`` declaration, a ``namespace`` declaration accepts
either identifiers or double-quoted strings as namespace names. E.g., the
following two declarations are equivalent:
``using`` 宣言と同じように、 ``namespace`` 宣言も、識別子とダブルクォートに挟まれた文字列の両方を名前空間名として受け入れます。例えば、次の二つの宣言は等価です::
namespace foo;
namespace "foo";
The latter form also allows more descriptive labels which aren't identifiers,
e.g.:
後者の形式では、もっと説明的なラベルを使うこともできます。これは識別子にはなりません::
namespace "Private stuff, keep out!";
Note that the namespace prefix in a qualified identifier must be a legal
identifier, so it isn't possible to access symbols in namespaces with such
descriptive labels in a direct fashion. The only way to get at the symbols in
this case is to use a ``namespace`` or ``using namespace`` declaration (for
the latter see `Using Namespaces`_ below).
修飾子つき識別子の前部分に置かれる名前空間プレフィクスは合法の識別子でなければなりません。なので、このように説明的なラベルを持つ名前空間内のシンボルに直接的なやり方でアクセスすることはできません。このような場合にそのシンボルへ到達する唯一の方法は、 ``namespace`` または ``using namespace`` 宣言を行うことです(後者については下の `Using Namespaces`_ を参照)。
Using Namespaces
~~~~~~~~~~~~~~~~
Using Namespaces
Since it is rather inconvenient if you always have to write identifiers in
their qualified form outside of their "home" namespace, Pure allows you to
specify a list of *search* namespaces which are used to look up symbols not in
the default or the current namespace. This is done with the ``using
namespace`` declaration, which takes the following form:
ある識別子を、それが「ホーム」としている名前空間の外で書くとき、いつも修飾子つきの形式で書かなければならないとしたら、いささか不便です。 Pure では *検索用* 名前空間のリストを定義することができ、デフォルト名前空間やカレント名前空間内に存在しないシンボルを探すために使われます。これを設定するには ``using namespace`` 宣言を行うのですが、次のような形式です::
using namespace name1, name2, ...;
// ...
using namespace;
(As with ``namespace`` declarations, the second form without any namespace
arguments gets you back to the default empty list of search namespaces.)
( ``namespace`` 宣言のときと同じように、2つめの形式には名前空間引数が一つもありませんが、これにより検索用名前空間のリストを空にし、デフォルトの状態へ戻しています)
For instance, consider this example:
例えば、この例を考えてみて下さい::
namespace foo;
foo x = x+1;
namespace bar;
foo x = x-1;
bar x = x+1;
namespace;
The symbols in these namespaces can be accessed unqualified as follows:
これらの名前空間内のシンボルは、次のように修飾子なしでアクセスできます::
> using namespace foo;
> foo 99;
100
> using namespace bar;
> foo 99;
98
> bar 99;
100
This method is often to be preferred over opening a namespace with the
``namespace`` declaration, since ``using namespace`` only gives you "read
access" to the imported symbols, so you can't accidentally mess up the
definitions of the namespace you're using. Another advantage is that the
``using namespace`` declaration also lets you search multiple namespaces at
once:
この方法はしばしば、 ``namespace`` 宣言を使って名前空間を開始した上で実行されます。なぜなら ``using namespace`` は、インポートされたシンボルに対する「読み込み専用アクセス権」だけをあなたに与えるからです。なので、現在使っている〔using している〕名前空間の定義を、あなたが誤ってめちゃくちゃにしてしまうことはあり得ません。もう一つの利点は、 ``using namespace`` 宣言で複数の名前空間を同時に検索対象とすることが可能になる点です::
using namespace foo, bar;
Be warned, however, that this brings up the very same issue of name clashes
again:
しかし、これにより名前衝突とほとんど同じ問題が再び起きうることも忘れないで下さい::
> using namespace foo, bar;
> foo 99;
<stdin>, line 15: symbol 'foo' is ambiguous here
In such a case you'll have to resort to using namespace qualifiers again, in
order to resolve the name clash:
このような場合には、再び名前空間修飾子を使い、名前衝突を解決しなければなりません::
> foo::foo 99;
100
To avoid this kind of mishap, you can also selectively import just a few
symbols from a namespace instead. This can be done with a declaration of the
following form:
このような災難を避けるため、これまでの方法の代わりに、名前空間から少数のシンボルだけを選んでインポートすることもできます。次のような形式の宣言で行います::
using namespace name1 ( sym1 sym2 ... ), name2 ... ;
As indicated, the symbols to be imported can optionally be placed as a
whitespace-delimited list inside parentheses, following the corresponding
namespace name. For instance:
これが示す通り、名前空間名の後に、インポートされるべきシンボルのリストを、丸括弧の間にホワイトスペースで区切って書くことで、選択的にインポートできます。例えば::
> using namespace foo, bar (bar);
> foo 99;
100
> bar 99;
100
> bar::foo 99;
98
Note that now we have no clash on the ``foo`` symbol any more, because we
restricted the import from the ``bar`` namespace to the ``bar`` symbol, so
that ``bar::foo`` has to be denoted with a qualified symbol now.
もはや ``foo`` シンボルの衝突は起こらなくなりました。インポート対象を ``bar`` 名前空間ではなくし、その中の ``bar`` シンボルだけに限定したからです。その結果、ここで ``bar::foo`` を指示するため修飾子つきシンボルを使う必要も生じています。
Symbol Lookup and Creation
~~~~~~~~~~~~~~~~~~~~~~~~~~
シンボル検索と作成
Pure's rules for looking up and creating symbols are fairly straightforward
and akin to those in other languages featuring namespaces. However, there are
some intricacies involved, because the rewriting rule format of definitions
allows "referential" use of symbols not only in the "body" (right-hand side)
of a definition, but also in the left-hand side patterns. We discuss this in
detail below.
Pure がシンボルを検索・作成するルールはとても素直なもので、名前空間を備える他の言語とも似ています。しかし、いくらか複雑な部分もあります。というのは、定義における書き換えルールのフォーマットはシンボルを "referential" に使うことができ、それは定義の "body" (右辺)内だけでなく、左辺のパターン内でも同じだからです。この点を以下で詳しく議論します。
The compiler searches for symbols first in the current namespace (if any),
then in the currently active search namespaces (if any), and finally in the
default (i.e., the global) namespace, in that order. This automatic lookup can
be bypassed by using an *absolute* namespace qualifier of the form
``::foo::bar``. In particular, ``::bar`` always denotes the symbol ``bar`` in
the default namespace, while ``::foo::bar`` denotes the symbol ``bar`` in the
``foo`` namespace. (Normally, the latter kind of notation is only needed if
you have to deal with nested namespaces, see `Hierarchical Namespaces`_
below.)
コンパイラはまず(もしあるなら)カレント名前空間のシンボルを探します。その後、(もしあるなら)現在アクティブな名前空間を探します。最後に、デフォルト名前空間(=グローバル名前空間)を探します。この自動探索は ``::foo::bar`` 形式の *絶対* 名前空間修飾子を使ってバイパスすることができます。特に ``::bar`` は常にデフォルト名前空間のシンボル ``bar`` を示し、 ``::foo::bar`` は ``foo`` 名前空間内の ``bar`` を示します(通常、後者の記法はネストされた名前空間を扱う場合のみ必要となるものです。詳しくは下部 Namespaces_ を参照)。
If no existing symbol is found, a new symbol is created automatically, by
implicitly declaring a public symbol with default attributes. New
*unqualified* symbols are always created in the current namespace, while new
*qualified* symbols are created in the namespace given by the namespace prefix
of the symbol. However, note that in the latter case the compiler always
checks that the given namespace prefix matches the current namespace:
もしシンボルが存在しなかったら、新しいシンボルが自動的に作られます。このとき、デフォルトの属性を持つ public なシンボルが暗黙のうちに宣言されます。 *修飾子なしの* 新しいシンボルは常にカレント名前空間に作られ、 *修飾子つきの* 新しいシンボルはシンボルの名前空間プレフィクスで与えられた名前空間に作られます。しかし後者の場合、コンパイラは、与えられた名前空間がカレント名前空間にマッチするかどうか常にチェックするということを覚えておいて下さい::
> namespace foo;
> namespace;
> foo::bar x = 1/x;
<stdin>, line 3: undeclared symbol 'foo::bar'
Thus it's only possible to introduce a new symbol in a given namespace if that
namespace is the current one. These error messages are somewhat annoying, but
they provide at least some protection against typos and other silly mistakes
and prevent you from accidentally clobbering the contents of other
namespaces. To make these errors go away it's enough to just declare the
symbols in their proper namespaces.
したがって、与えられた名前空間に新しいシンボルを導入することができるのは、その名前空間がカレント名前空間である場合だけだということです。この種のラーメッセージはいささかわずらわしいですが、少なくともミスタイプなどのバカバカしい間違いや、他の名前空間の中身を意図せずぶん殴ってしまうことを防いでくれます。このエラーを遠ざけるには、そのシンボルにとって適切な名前空間をきちんと宣言するだけで充分なのです。
New symbols are also created if a global unqualified (and yet undeclared)
symbol is being "defined" in a rewriting rule or ``let``/``const`` definition,
even if a symbol with the same print name from another namespace is already
visible in the current scope. To distinguish "defining" from "referring" uses
of a global symbol, Pure uses the following (purely syntactic) notions:
また、修飾子なしのグローバルな(かつ未宣言の)シンボルが、書き換えルール内や ``let``/``const`` 定義内で「定義され」ている場合、新しいシンボルが作られます。他の名前空間に属しながら同じ表示名を持つシンボルが現在のスコープ内でvisibleであったとしても、作られます。グローバルシンボルの「定義する」ことと「参照する」ことを区別するため、 Pure では次のような(純粋に統語的な)記法を使います:
* A `defining occurrence` of a global *function* or *macro symbol* is any
occurrence of the symbol as the *head symbol* on the left-hand side of a
rewriting rule.
* グローバルな *関数* またはグローバルな *マクロシンボル* の `定義の出現` 〔 `defining occurrence` 〕は、書き換えルール左辺において、シンボルが *先頭シンボル* 〔 *head symbol* 〕として出現することである。
* A `defining occurrence` of a global *variable* or *constant symbol* is any
occurrence of the symbol in a *variable position* (as given by the "head =
function" rule, cf. `Parameters in Equations`_) on the left-hand side of a
``let`` or ``const`` definition.
* グローバル *変数* またはグローバル *定数シンボル* の `定義の出現` は、 ``let`` または ``const`` 定義の左辺において、シンボルが *変数の位置* に現れることである(「先頭=関数」ルールに従っている。 cf. `Parameters in Equations`_ )。
* All other occurrences of global symbols on the left-hand side, as well as
*all* symbol occurrences on the right-hand side of a definition are
`referring occurrences`.
* 定義左辺における他のあらゆるグローバルシンボルの出現、および定義右辺における *あらゆる* シンボルの発生は、 `参照的な出現` である。
The following example illustrates these notions:
次の例がこれらの記法を説明してくれます::
namespace foo;
bar (bar x) = bar x;
let x,y = 1,2;
namespace;
Here, the first occurrence of ``bar`` on the left-hand side ``bar (bar x)`` of
the first rule is a *defining* occurrence, as are the occurrences of ``x`` and
``y`` on the left-hand side of the ``let`` definition. Hence these symbols are
created as new symbols in the namespace ``foo``. On the other hand, the other
occurrences of ``bar`` in the first rule, as well as the '\ ``,``\ ' symbol on
the left-hand side of the ``let`` definition are *referring* occurrences. In
the former case, ``bar`` refers to the ``bar`` symbol defined by the rule,
while in the latter case the '\ ``,``\ ' operator is actually declared in the
prelude and thus imported from the global namespace.
この場合、最初のルールの左辺 ``bar (bar x)`` 内にある最初の ``bar`` は *定義的な* 出現であり、 ``let`` 定義内にある ``x`` と ``y`` も同様です。したがって、これらのシンボルは新たなシンボルとして名前空間 ``foo`` 内に作られます。それに対して、最初のルールで現れているもう一つの ``bar`` は、 ``let`` 定義の左辺にある '\ ``,``\ ' と同じく、 *参照的な* 出現です。前者 [#]_ の場合、 ``bar`` はそのルールによって定義された ``bar`` シンボルを指示しています。後者の場合、 '\ ``,``\ ' 演算子が実際に定義されているのは prelude 内であり、グローバル名前空間からインポートされています。
.. [#] 訳注:最初のルール左辺にある3つの bar のうち2番目の(=丸括弧内にある) ``bar`` のこと。
Note that special operator (and nonfix) symbols *always* require an explicit
declaration. This works as already discussed in the `Symbol Declarations`_
section, except that you first switch to the appropriate namespace before
declaring the symbols. For instance, here is how you can create a new ``+``
operation which multiplies its operands rather than adding them:
特別な演算子の(およびノンフィクスの)シンボルは *常に* 明示的な宣言を必要とすることを忘れないで下さい。この動作については `Symbol Declarations`_ セクションですでに述べた通りですが、シンボル宣言を行う前にまずappropriateな名前空間へと変更を行った場合は話が別です。例として、新しく ``+`` 演算を作り、それが加算でなく乗算を行うようにする方法を示します::
> namespace my;
> infixl 2100 +;
> x+y = x*y;
> 5+7;
35
Note that the new ``+`` operation really belongs to the namespace we
created. The ``+`` operation in the default namespace works as before, and in
fact you can use qualified symbols to pick the version that you need:
この新しい ``+`` 演算が、私たちの作った名前空間に所属していることに注意を向けて下さい。デフォルト名前空間に属する ``+`` 演算も今まで通り動作するので、修飾子つきシンボルを使えば、実際にあなたの求めに応じたバージョンの ``+`` 演算を使い分けることができます::
> namespace;
> 5+7;
12
> 5 ::+ 7;
12
> 5 my::+ 7;
35
Here's what you get if you happen to forget the declaration of the ``+``
operator:
``+`` 演算子を定義し忘れてしまったら、こういうことになります::
> namespace my;
> x+y = x*y;
<stdin>, line 2: infixl symbol '+' was not declared in this namespace
Thus the compiler will never create a new instance of an operator symbol on
the fly, an explicit declaration is always needed in such cases.
このように、コンパイラが演算子シンボルの新しいインスタンスをオン・ザ・フライで作成することは決してありません。こうした場合には明示的な宣言が必要なのです。
Note that if you *really* wanted to redefine the global ``+`` operator, you
can do this even while the ``my`` namespace is current. You just have to use a
qualified identifier in this case, as follows:
もしグローバルな ``+`` 演算子を再定義することが *本当に* 必要なら、可能ではあります。 ``my`` 名前空間がカレントであるときでさえも、です。このような場合、修飾子つき識別子を使う必要があります。次のように::
> namespace my;
> x ::+ y = x*y;
> a+b;
a*b
This should rarely be necessary (in the above example you might just as well
enter this rule while in the global namespace), but it can be useful in some
circumstances. Specifically, you might want to "overload" a global function
or operator with a definition that makes use of private symbols of a namespace
(which are only visible inside that namespace; see `Private Symbols`_
below). For instance:
これが必要になることはほとんどないでしょう(上の例を実際に使うなら、グローバル名前空間内でこのルールを入力するほうがよいでしょう)が、時と場合によっては便利でもあります。特に、グローバル関数やグローバル演算子を「オーバーロード」し、ある名前空間内のプライベートなシンボルとして使うのに役立てたいと思うことはあるかもしれません(その演算子はその名前空間内だけで見えるものです。下部 `Private Symbols`_ 参照)。例えば::
> namespace my;
> private bar;
> bar x y = x*y;
> x ::+ y = bar x y;
> a+b;
a*b
(The above is a rather contrived example, since the very same functionality
can be accomplished much easier, but there are some situations where this
approach is necessary.)
(上の例はやや不自然です。なぜなら、ほぼ同じ機能をもっと簡単に実現できるからです。しかし、このようなアプローチが必要となる状況もあります)
Private Symbols
~~~~~~~~~~~~~~~
Pure also allows you to have private symbols, as a means to hide away internal
operations which shouldn't be accessed directly outside the namespace in which
they are declared. The scope of a private symbol is confined to its namespace,
i.e., the symbol is only visible when its "home" namespace is current. Symbols
are declared private by using the ``private`` keyword in the symbol
declaration:
Pure ではプライベートなシンボルを持つことも許されます。シンボルが属する名前空間の外から直接アクセスされてはいけない処理を隠す手段となっています。プライベートシンボルのスコープは、それが属す名前空間内に限定されます。すなわち、そのシンボルの「ホーム」名前空間がカレント状態であるときだけ可視となります。シンボルをプライベートなものとして宣言するには、宣言時に ``private`` キーワードを使います::
> namespace secret;
> private baz;
> // 'baz' is a private symbol in namespace 'secret' here
> baz x = 2*x;
> // you can use 'baz' just like any other symbol here
> baz 99;
198
> namespace;
Note that, at this point, ``secret::baz`` is now invisible, even if you have
``secret`` in the search namespace list:
この段階で、 ``secret::baz`` は不可視の状態です。たとえ ``secret`` が検索対象の名前空間リストに入っていても、見えません::
> using namespace secret;
> // this actually creates a 'baz' symbol in the default namespace:
> baz 99;
baz 99
> secret::baz 99;
<stdin>, line 27: symbol 'secret::baz' is private here
The only way to bring the symbol back into scope is to make the ``secret``
namespace current again:
このシンボルをスコープ内へと戻すには、 ``secret`` 名前空間を再びカレントにするしかありません::
> namespace secret;
> baz 99;
198
> secret::baz 99;
198
Hierarchical Namespaces
~~~~~~~~~~~~~~~~~~~~~~~
階層状の名前空間
Namespace identifiers can themselves be qualified identifiers in Pure, which
enables you to introduce a hierarchy of namespaces. This is useful, e.g., to
group related namespaces together under a common "umbrella" namespace:
Pure では、名前空間識別子は、それ自身が修飾子つき識別子であることも可能です。これにより、名前空間の階層を導入することができるようになっています。これが便利なのは、例えば、関連する複数の名前空間を、共通の "umbrella" 名前空間の下にまとめる場合です::
namespace my;
namespace my::old;
foo x = x+1;
namespace my::new;
foo x = x-1;
Note that the namespace ``my``, which serves as the parent namespace, must be
created before the ``my::old`` and ``my::new`` namespaces, even if it does not
contain any symbols of its own. After these declarations, the ``my::old`` and
``my::new`` namespaces are part of the ``my`` namespace and will be considered
in name lookup accordingly, so that you can write:
名前空間 ``my`` は、親の名前空間となっていますが、 ``my::old`` や ``my::new`` よりも前に作成されなければならないことを忘れないで下さい。親となる名前空間がシンボルを一つも持っていない場合でもです。これらの宣言の後、 ``my::old`` と ``my::new`` 名前空間は ``my`` 名前空間の一部となり、名前探索の際にもそれに応じた考慮が行われます。なので、次のように書くことができます::
> using namespace my;
> old::foo 99;
100
> new::foo 99;
98
This works pretty much like a hierarchy of directories and files, where the
namespaces play the role of the directories (with the default namespace as the
root directory), the symbols in each namespace correspond to the files in a
directory, and the ``using namespace`` declaration functions similar to the
shell's ``PATH`` variable.
この動作は、ディレクトリやファイルの階層構造ととてもよく似ています。この場合、各名前空間はディレクトリ(デフォルト名前空間をルートディレクトリとする)の役割を果たし、名前空間内の各シンボルはディレクトリ内のファイルに対応します。 ``using namespace`` 宣言はシェルの ``PATH`` 変数と同じように機能します。
Sometimes it is necessary to tell the compiler to use a symbol in a specific
namespace, bypassing the usual symbol lookup mechanism. For instance, suppose
that we introduce another *global* ``old`` namespace and define yet another
version of ``foo`` in that namespace:
ときどき、通常のシンボル検索手順を避けて、特定の名前空間内のシンボルを使うようコンパイラに伝える必要が生じます。例えば、 *グローバルな* ``old`` 名前空間をもう一つ導入し、その名前空間内に別バージョンの ``foo`` を定義することを考えます::
namespace old;
foo x = 2*x;
namespace;
Now, if we want to access that function, with ``my`` still active as the
search namespace, we cannot simply refer to the new function as ``old::foo``,
since this name will resolve to ``my::old::foo`` instead. As a remedy, the
compiler accepts an `absolute` qualified identifier of the form
``::old::foo``. This bypasses name lookup and thus always yields exactly the
symbol in the given namespace (if it exists; as mentioned previously, the
compiler will complain about an undeclared symbol otherwise):
今、この関数へアクセスしたいとして、しかも ``my`` 名前空間がまだ検索対象として有効であるとしても、単純に ``old::foo`` としただけでは新しい関数へアクセスできません。代わりに ``my::old::foo`` と解決されてしまうからです。改善策として、コンパイラは ``::old::foo`` という形式の `絶対指定` 修飾子つき識別子を受け入れます。これは名前空間検索を迂回するので、与えられた名前空間をいつでも正確にもたらしてくれます(もし存在するならば、ですが。前でも述べましたが、存在しない場合、コンパイラは未宣言のシンボルだと文句を言ってきます)::
> old::foo 99;
100
> ::old::foo 99;
198
Also note that, as a special case of the absolute qualifier notation,
``::foo`` always denotes the symbol ``foo`` in the default namespace.
また、絶対指定修飾子記法の特別ケースとして、 ``::foo`` は常にデフォルト名前空間内のシンボルを指示するものであることを覚えておいて下さい。
Scoped Namespaces
~~~~~~~~~~~~~~~~~
Pure also provides an alternative scoped ``namespace`` construct which makes
nested namespace definitions more convenient. This construct takes the
following form:
また Pure は、もう一つ別のスコープを持つ ``namespace`` 構造を提供します。これはネストされた名前空間定義を便利に行う方法です。この構造は次のような形式をとります::
namespace name with ... end;
The part between ``with`` and ``end`` may contain arbitrary declarations and
definitions, using the same syntax as the toplevel. These are processed in the
context of the given namespace, as if you had written:
``with`` から ``end`` までの間には、任意の宣言と定義を入れてかまいません。トップレベルと同じ文法を使えます。それらは与えられた名前空間の文脈で処理され、以下のように書いた場合と同じ効果を持ちます::
namespace name;
...
namespace;
However, the scoped namespace construct always returns you to the namespace
which was active before, and thus these declarations may be nested:
しかし、スコープを持つ名前空間構造は、その直前にアクティブであった名前空間へと常に戻ります。なので、このように宣言を重箱のようにする〔=ネストする〕ことができます::
namespace foo with
// declarations and definitions in namespace foo
namespace bar with
// declarations and definitions in namespace bar
end;
// more declarations and definitions in namespace foo
end;
Note that this kind of nesting does not necessarily imply a namespace
hierarchy as discussed in `Hierarchical Namespaces`_. However, you can achieve
this by using the appropriate qualified namespace names:
この種のネスティングは、 `Hierarchical Namespaces`_ で議論したような階層状の名前空間を必ずしも伴うものではないことに注意して下さい。階層状の名前空間を実現するには適切な修飾子つき名前空間名を使います::
namespace foo with
// ...
namespace foo::bar with
// ...
end;
// ...
end;
Another special feature of the scoped namespace construct is that ``using
namespace`` declarations are always local to the current namespace scope (and
other nested namespace scopes inside it). Thus the previous setting is
restored at the end of each scope:
もうひとつ、スコープを持つ名前空間構造には特色があります。 ``using namespace`` 宣言は常にカレント名前空間スコープへと(かつ、その内側に含まれる入れ子の名前空間スコープへと)ローカルであるということです。したがって、さきほどの設定は各スコープの末尾で復旧されます::
using namespace foo;
namespace foo with
// still using namespace foo here
// ここではまだ foo 名前空間を使用中
using namespace bar;
// now using namespace bar
// 今は bar 名前空間を使用中
namespace bar with
// still using namespace bar here
// まだ bar
using namespace foo;
// now using namespace foo
// foo を使用中
end;
// back to using namespace bar
// bar に戻った
end;
// back to using namespace foo at toplevel
// トップレベルの foo に戻った
Finally, here's a more concrete example which shows how scoped namespaces
might be used to declare two namespaces and populate them with various
functions and operators:
最後に、もっと具体的な例を示します。この例は、スコープを持つ名前空間内を使って、2つの名前空間を宣言し、それらを様々な関数や演算子とともに住まわせる方法を示しています::
namespace foo with
infixr (::^) ^;
foo x = x+1;
bar x = x-1;
x^y = 2*x+y;
end;
namespace bar with
outfix <: :>;
foo x = x+2;
bar x = x-2;
end;
using namespace foo(^ foo), bar(bar <: :>);
// namespace foo
foo x;
x^y;
// namespace bar
bar x;
<: x,y :>;
Pure's namespaces can thus be used pretty much like "modules" or "packages" in
languages like Ada or Modula-2. They provide a structured way to describe
program components offering collections of related data and operations, which
can be brought into scope in a controlled way by making judicious use of
``using namespace`` declarations. They also provide an abstraction barrier,
since internal operations and data structures can be hidden away employing
private symbols.
Pure の名前空間はこのように、 Ada や Modula-2 の「モジュール」や「パッケージ」ととてもよく似た使い方ができます。それらは、複数のプログラム構成要素を構造的に記述する手段であり、関連するデータと処理をまとめた状態で提供できるようにしてくれます。 ``using namespace`` 宣言を賢明に使えば、それらを適切に管理しながらスコープ内へ導くことができます。また、 ``using namespace`` 宣言は抽象的な仕切りをも提供します。プライベートシンボルを使うことで内部処理や