Lisp-quick-guide

提供:Dev Guides
移動先:案内検索

LISP-概要

ジョンマッカーシーは、FORTRANの開発直後の1958年にLISPを発明しました。 これは、IBM 704コンピューターでSteve Russellによって最初に実装されました。

シンボリック情報を効果的に処理するため、人工知能プログラムに特に適しています。

Common Lispは、1980年代と1990年代に、ZetaLispやNIL(Lispの新しい実装)など、Maclispの後継であるいくつかの実装グループの作業を統合しようとして生まれました。

これは、特定の実装用に簡単に拡張できる共通言語として機能します。

Common LISPで記述されたプログラムは、語長などのマシン固有の特性に依存しません。

Common LISPの機能

  • マシンに依存しません
  • 反復的な設計方法論と簡単な拡張性を使用します。
  • プログラムを動的に更新できます。
  • 高レベルのデバッグを提供します。
  • 高度なオブジェクト指向プログラミングを提供します。
  • 便利なマクロシステムを提供します。
  • オブジェクト、構造、リスト、ベクトル、調整可能な配列、ハッシュテーブル、シンボルなどの幅広いデータ型を提供します。
  • 式ベースです。
  • オブジェクト指向の条件システムを提供します。
  • 完全なI/Oライブラリを提供します。
  • 広範な制御構造を提供します。

LISPに組み込まれたアプリケーション

Lispで構築された大成功のアプリケーション。

  • Emacs
  • G2
  • AutoCad
  • イゴール彫刻家
  • ヤフーストア

LISP-環境設定

ローカル環境のセットアップ

Lispプログラミング言語用に環境をセットアップする場合は、コンピューター上で次の2つのソフトウェア、(a)Text Editorおよび(b)The Lisp Executerが必要です。

テキストエディタ

これは、プログラムの入力に使用されます。 いくつかのエディターの例には、Windows Notepad、OS Editコマンド、Brief、Epsilon、EMACS、vimまたはviが含まれます。

テキストエディタの名前とバージョンは、オペレーティングシステムによって異なる場合があります。 たとえば、メモ帳はWindowsで使用され、vimまたはviはLinuxまたはUNIXだけでなくWindowsでも使用できます。

エディターで作成するファイルはソースファイルと呼ばれ、プログラムのソースコードが含まれています。 Lispプログラムのソースファイルには、通常、拡張子「 .lisp 」が付いています。

プログラミングを開始する前に、テキストエディタが1つあることを確認し、コンピュータプログラムを作成し、ファイルに保存し、最後に実行する十分な経験があることを確認してください。

Lisp実行者

ソースファイルに記述されたソースコードは、プログラムの人間が読めるソースです。 CPUが指定された指示に従って実際にプログラムを実行できるように、機械語に変換するには「実行」する必要があります。

このLispプログラミング言語は、ソースコードを実行して最終的な実行可能プログラムにするために使用されます。 プログラミング言語に関する基本的な知識があることを前提としています。

CLISPは、WindowsでLISPをセットアップするために使用されるGNU Common LISPマルチアーキテクチャコンパイラです。 Windowsバージョンは、WindowsでMingWを使用してUNIX環境をエミュレートします。 インストーラーがこれを処理し、clispをWindowsのPATH変数に自動的に追加します。

ここからWindows用の最新のCLISPを入手できます-https://sourceforge.net/projects/clisp/files/latest/download

LIST環境設定

デフォルトでは、行ごとのインタープリター用にショートカットが[スタート]メニューに作成されます。

CLISPの使用方法

インストール中、オプションを選択すると、 clisp がPATH変数に自動的に追加されます(推奨)。これは、新しいコマンドプロンプトウィンドウを開き、「clisp」と入力してコンパイラを起動できることを意味します。

  • .lispまたは* .lspファイルを実行するには、単に使用します-
clisp hello.lisp

LISP-プログラム構造

LISP式は、シンボリック式またはs式と呼ばれます。 s-expressionsは、3つの有効なオブジェクト、アトム、リスト、および文字列で構成されています。

すべてのs式は有効なプログラムです。

LISPプログラムは、*インタープリター*または*コンパイル済みコード*で実行されます。

インタープリターは、反復評価ループでソースコードをチェックします。これは、読み取り-評価-印刷ループ(REPL)とも呼ばれます。 プログラムコードを読み取り、評価し、プログラムから返された値を出力します。

簡単なプログラム

s-expressionを記述して、3つの数値7、9、および11の合計を見つけましょう。 これを行うには、インタープリタープロンプトで入力します。

(+ 7 9 11)

LISPは結果を返します-

27

コンパイルされたコードと同じプログラムを実行する場合は、myprog.lispという名前のLISPソースコードファイルを作成し、その中に次のコードを入力します。

(write (+ 7 9 11))

実行ボタンをクリックするか、Ctrl + Eを入力すると、LISPはすぐに実行し、返される結果は-

27

LISPはプレフィックス表記を使用します

LISPは* prefix notation。*を使用していることに気づいたかもしれません。

上記のプログラムでは、+記号は数字の合計プロセスの関数名として機能します。

プレフィックス表記では、演算子はオペランドの前に記述されます。 たとえば、式

a * ( b + c )/d

として書かれます-

(/( *a (+ b c) ) d)

別の例を見てみましょう、60 ^ o ^ Fの華氏温度を摂氏スケールに変換するコードを書きましょう-

この変換の数式は次のようになります-

(60* 9/5) + 32

main.lispという名前のソースコードファイルを作成し、次のコードを入力します。

(write(+ (* (/9 5) 60) 32))

[実行]ボタンをクリックするか、Ctrl + Eを入力すると、LISPはすぐに実行し、返される結果は-

140

LISPプログラムの評価

LISPプログラムの評価には2つの部分があります-

  • リーダープログラムによるプログラムテキストのLispオブジェクトへの翻訳
  • 評価プログラムによるこれらのオブジェクトに関する言語のセマンティクスの実装

評価プロセスは、次の手順を実行します-

  • リーダーは、文字列をLISPオブジェクトまたは s-expressions に変換します。 評価者は、s式から構築されるLisp フォーム*の構文を定義します。 この第2レベルの評価では、どの s-expressions がLISP形式であるかを決定する構文を定義します。
  • 評価者は、有効なLISP形式を引数として受け取り、値を返す関数として機能します。 これが、式/フォーム全体を引数として評価者に送信しているため、LISP式をかっこで囲む理由です。

「Hello World」プログラム

新しいプログラミング言語を学ぶことは、その言語で全世界に挨拶する方法を学ぶまで、実際にはうまくいきません!

したがって、main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力してください。

(write-line "Hello World")

(write-line "I am at 'Tutorials Point'! Learning LISP")

実行ボタンをクリックするか、Ctrl + Eを入力すると、LISPはすぐに実行し、返される結果は-

Hello World

I am at 'Tutorials Point'! Learning LISP

LISP-基本的な構文

LISPの基本的な構成要素

LISPプログラムは3つの基本的なビルディングブロックで構成されています-

  • atom

  • list

  • ひも

    *atom* は、連続する文字の数または文字列です。 数字と特殊文字が含まれています。

以下は、いくつかの有効な原子の例です-

hello-from-tutorials-point
name
123008907
*hello*
Block#221
abc123
  • リスト*は、括弧で囲まれた一連のアトムおよび/または他のリストです。

以下はいくつかの有効なリストの例です-

( i am a list)
(a ( a b c) d e fgh)
(father tom ( susan bill joe))
(sun mon tue wed thur fri sat)
( )
*string* は、二重引用符で囲まれた文字のグループです。

以下は、いくつかの有効な文字列の例です-

" I am a string"
"a ba c d efg #$%^&!"
"Please enter the following details :"
"Hello from 'Tutorials Point'! "

コメントを追加する

セミコロン記号(;)は、コメント行を示すために使用されます。

例えば、

(write-line "Hello World") ; greet the world

; tell them your whereabouts

(write-line "I am at 'Tutorials Point'! Learning LISP")

実行ボタンをクリックするか、Ctrl + Eを入力すると、LISPはすぐに実行し、返される結果は-

Hello World

I am at 'Tutorials Point'! Learning LISP

次へ進む前の注目すべきポイント

以下は、注意すべき重要な点の一部です-

  • LISPの基本的な数値演算は、+、-、*、および/です。
  • LISPは、関数呼び出しf(x)を(f x)として表します。たとえば、cos(45)はcos 45として記述されます。
  • LISP式は大文字と小文字を区別せず、cos 45またはCOS 45は同じです。
  • LISPは、関数の引数を含むすべてを評価しようとします。 3種類の要素のみが定数であり、常に独自の値を返します
  • 番号
  • 論理的な真を表す文字* t、*。
  • 空のリストと同様に、論理falseを表す値* nil、*。

LISPフォームについてもう少し

前の章で、LISPコードの評価プロセスは次のステップを踏むことを述べました。

  • リーダーは、文字列をLISPオブジェクトまたは s-expressions に変換します。 評価者は、s式から構築されるLisp フォーム*の構文を定義します。 この第2レベルの評価は、どのS式がLISP形式であるかを決定する構文を定義します。

これで、LISPフォームが可能になります。

  • アトム
  • 空または非リスト
  • 最初の要素として記号を含むリスト

評価者は、有効なLISP形式を引数として受け取り、値を返す関数として機能します。 これが、式/フォーム全体を引数として評価者に送信しているため、* LISP式をかっこで囲む理由です。

LISPの命名規則

名前または記号は、空白、開き括弧と閉じ括弧、二重引用符と単一引用符、バックスラッシュ、コンマ、コロン、セミコロン、垂直バー以外の任意の数の英数字で構成できます。 名前にこれらの文字を使用するには、エスケープ文字(\)を使用する必要があります。

名前には数字を含めることができますが、数字だけで読み取られるため、完全に数字で構成されるわけではありません。 同様に、名前にピリオドを含めることができますが、ピリオドだけで名前を作成することはできません。

単一引用符の使用

LISPは、関数の引数やリストメンバーを含むすべてを評価します。

時には、文字どおりアトムまたはリストを取得する必要があり、それらを評価したり、関数呼び出しとして処理したりしないようにします。

これを行うには、アトムまたはリストの前に単一引用符を付ける必要があります。

次の例はこれを示しています。

main.lispという名前のファイルを作成し、次のコードを入力します。

(write-line "single quote used, it inhibits evaluation")
(write '(* 2 3))
(write-line " ")
(write-line "single quote not used, so expression evaluated")
(write (* 2 3))

実行ボタンをクリックするか、Ctrl + Eを入力すると、LISPはすぐに実行し、返される結果は-

single quote used, it inhibits evaluation
(* 2 3)
single quote not used, so expression evaluated
6

LISP-データ型

LISPでは、変数は入力されませんが、データオブジェクトは入力されます。

LISPデータ型は次のように分類できます。

  • スカラー型-たとえば、数値型、文字、記号など
  • データ構造-たとえば、リスト、ベクトル、ビットベクトル、文字列。

明示的に宣言していない限り、どの変数もその値として任意のLISPオブジェクトを取ることができます。

ただし、LISP変数のデータ型を指定する必要はありませんが、特定のループ展開、メソッド宣言、および後の章で説明するその他の状況で役立ちます。

データ型は階層に配置されます。 データタイプはLISPオブジェクトのセットであり、多くのオブジェクトはそのようなセットの1つに属する場合があります。

*typep* 述語は、オブジェクトが特定のタイプに属するかどうかを見つけるために使用されます。
*type-of* 関数は、指定されたオブジェクトのデータ型を返します。

LISPのタイプ指定子

型指定子は、データ型のシステム定義のシンボルです。

array fixnum package simple-string
atom float pathname simple-vector
bignum function random-state single-float
bit hash-table ratio standard-char
bit-vector integer rational stream
character keyword readtable string
[common] list sequence [string-char]
compiled-function long-float short-float symbol
complex nill signed-byte t
cons null simple-array unsigned-byte
double-float number simple-bit-vector vector

これらのシステム定義型とは別に、独自のデータ型を作成できます。 defstruct 関数を使用して構造タイプが定義されている場合、構造タイプの名前は有効なタイプシンボルになります。

例1

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq x 10)
(setq y 34.567)
(setq ch nil)
(setq n 123.78)
(setq bg 11.0e+4)
(setq r 124/2)

(print x)
(print y)
(print n)
(print ch)
(print bg)
(print r)

実行ボタンをクリックするか、Ctrl + Eを入力すると、LISPはすぐに実行し、返される結果は-

10
34.567
123.78
NIL
110000.0
62

例2

次に、前の例で使用した変数のタイプを確認しましょう。 mainという名前の新しいソースコードファイルを作成します。 lispに次のコードを入力します。

(defvar x 10)
(defvar y 34.567)
(defvar ch nil)
(defvar n 123.78)
(defvar bg 11.0e+4)
(defvar r 124/2)

(print (type-of x))
(print (type-of y))
(print (type-of n))
(print (type-of ch))
(print (type-of bg))
(print (type-of r))

実行ボタンをクリックするか、Ctrl + Eを入力すると、LISPはすぐに実行し、返される結果は-

(INTEGER 0 281474976710655)
SINGLE-FLOAT
SINGLE-FLOAT
NULL
SINGLE-FLOAT
(INTEGER 0 281474976710655)

LISP-マクロ

マクロを使用すると、標準のLISPの構文を拡張できます。

技術的には、マクロは引数としてs-expressionを取り、評価されるLISPフォームを返す関数です。

マクロを定義する

LISPでは、名前付きマクロは、* defmacro。*という名前の別のマクロを使用して定義されます。マクロを定義するための構文は-

(defmacro macro-name (parameter-list))
"Optional documentation string."
body-form

マクロ定義は、マクロの名前、パラメーターリスト、オプションのドキュメント文字列、およびマクロによって実行されるジョブを定義するLisp式の本体で構成されます。

setTo10という名前の簡単なマクロを作成してみましょう。このマクロは数値を取得し、その値を10に設定します。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defmacro setTo10(num)
(setq num 10)(print num))
(setq x 25)
(print x)
(setTo10 x)

実行ボタンをクリックするか、Ctrl + Eを入力すると、LISPはすぐに実行し、返される結果は-

25
10

LISP-変数

LISPでは、各変数は*記号*で表されます。 変数の名前はシンボルの名前であり、シンボルのストレージセルに保存されます。

グローバル変数

グローバル変数はLISPシステム全体で永続的な値を持ち、新しい値が指定されるまで有効です。

通常、グローバル変数は defvar 構造を使用して宣言されます。

例えば

(defvar x 234)
(write x)

[実行]ボタンをクリックするか、Ctrl + Eを入力すると、LISPはすぐに実行し、返される結果は

234

LISPには変数の型宣言がないため、 setq コンストラクトでシンボルの値を直接指定します。

例えば

->(setq x 10)

上記の式は、値10を変数xに割り当てます。 式としてシンボル自体を使用して、変数を参照できます。

*symbol-value* 関数を使用すると、シンボルの保存場所に保存されている値を抽出できます。

例えば

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq x 10)
(setq y 20)
(format t "x = ~2d y = ~2d ~%" x y)

(setq x 100)
(setq y 200)
(format t "x = ~2d y = ~2d" x y)

[実行]ボタンをクリックするか、Ctrl + Eを入力すると、LISPがすぐに実行し、返される結果が返されます。

x = 10 y = 20
x = 100 y = 200

ローカル変数

ローカル変数は、特定のプロシージャ内で定義されます。 関数定義内の引数として指定されたパラメーターもローカル変数です。 ローカル変数は、それぞれの関数内でのみアクセス可能です。

グローバル変数と同様に、ローカル変数も setq コンストラクトを使用して作成できます。

ローカル変数を作成するための letprog の2つの構造があります。

let構文の構文は次のとおりです。

(let ((var1  val1) (var2  val2).. (varn  valn))<s-expressions>)

ここで、var1、var2、.. varnは変数名、val1、val2、.. valnは、それぞれの変数に割り当てられた初期値です。

*let* が実行されると、各変数にそれぞれの値が割り当てられ、最後に_s-expression_が評価されます。 最後に評価された式の値が返されます。

変数の初期値を含めない場合、* nil。*に割り当てられます

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(let ((x 'a) (y 'b)(z 'c))
(format t "x = ~a y = ~a z = ~a" x y z))

[実行]ボタンをクリックするか、Ctrl + Eを入力すると、LISPがすぐに実行し、返される結果が返されます。

x = A y = B z = C
*prog* コンストラクトには、最初の引数としてローカル変数のリストがあり、その後に* prog、*の本体と任意の数のs-expressionが続きます。
*prog* 関数は、s-expressionのリストを順番に実行し、* return。*という名前の関数呼び出しが発生しない限り、nilを返します。その後、 *return* 関数の引数が評価されて返されます。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(prog ((x '(a b c))(y '(1 2 3))(z '(p q 10)))
(format t "x = ~a y = ~a z = ~a" x y z))

[実行]ボタンをクリックするか、Ctrl + Eを入力すると、LISPがすぐに実行し、返される結果が返されます。

x = (A B C) y = (1 2 3) z = (P Q 10)

LISP-定数

LISPでは、定数はプログラムの実行中に値を変更しない変数です。 定数は defconstant コンストラクトを使用して宣言されます。

次の例は、グローバル定数PIを宣言し、後で円の面積を計算する_area-circle_という名前の関数内でこの値を使用することを示しています。

*defun* コンストラクトは関数の定義に使用されます。これについては*関数*の章で説明します。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defconstant PI 3.141592)
(defun area-circle(rad)
   (terpri)
   (format t "Radius: ~5f" rad)
   (format t "~%Area: ~10f" (* PI rad rad)))
(area-circle 10)

[実行]ボタンをクリックするか、Ctrl + Eを入力すると、LISPがすぐに実行し、返される結果が返されます。

Radius:  10.0
Area:   314.1592

LISP-オペレーター

演算子は、特定の数学的または論理的な操作を実行するようコンパイラーに指示する記号です。 LISPでは、さまざまな機能、マクロ、およびその他の構成要素によってサポートされる、データに対する多数の操作が可能です。

データで許可された操作は次のように分類できます-

  • 算術演算
  • 比較操作
  • 論理演算
  • ビット演算

算術演算

次の表は、LISPでサポートされているすべての算術演算子を示しています。 変数 A が10を保持し、変数 B が20を保持すると仮定します-

*link:/lisp/lisp_arithmetic_operators [例を表示]*
Operator Description Example
+ Adds two operands (+A B) will give 30
- Subtracts second operand from the first (- A B) will give -10
* Multiplies both operands (* A B) will give 200
/ Divides numerator by de-numerator (/B A) will give 2
mod,rem Modulus Operator and remainder of after an integer division (mod B A )will give 0
incf Increments operator increases integer value by the second argument specified (incf A 3) will give 13
decf Decrements operator decreases integer value by the second argument specified (decf A 4) will give 9

比較操作

次の表は、数値を比較するLISPがサポートするすべての関係演算子を示しています。 ただし、他の言語の関係演算子とは異なり、LISP比較演算子は3つ以上のオペランドを取ることができ、数字のみで機能します。

変数 A が10を保持し、変数 B が20を保持すると仮定します-

*link:/lisp/lisp_comparison_operators [例を表示]*
Operator Description Example
= Checks if the values of the operands are all equal or not, if yes then condition becomes true. (= A B) is not true.
/= Checks if the values of the operands are all different or not, if values are not equal then condition becomes true. (/= A B) is true.
> Checks if the values of the operands are monotonically decreasing. (> A B) is not true.
< Checks if the values of the operands are monotonically increasing. (< A B) is true.
>= Checks if the value of any left operand is greater than or equal to the value of next right operand, if yes then condition becomes true. (>= A B) is not true.
Checks if the value of any left operand is less than or equal to the value of its right operand, if yes then condition becomes true. (⇐ A B) is true.
max It compares two or more arguments and returns the maximum value. (max A B) returns 20
min It compares two or more arguments and returns the minimum value. (min A B) returns 10

ブール値の論理演算

Common LISPは、ブール値を操作する* and、or、、 *not の3つの論理演算子を提供します。 A の値がnilで、 B の値が5であると仮定します-

*link:/lisp/lisp_logical_operators [例を表示]*
Operator Description Example
and It takes any number of arguments. The arguments are evaluated left to right. If all arguments evaluate to non-nil, then the value of the last argument is returned. Otherwise nil is returned. (and A B) will return NIL.
or It takes any number of arguments. The arguments are evaluated left to right until one evaluates to non-nil, in such case the argument value is returned, otherwise it returns nil. (or A B) will return 5.
not It takes one argument and returns t *if the argument evaluates to nil.* (not A) will return T.

数値のビット演算

ビットごとの演算子はビットに対して機能し、ビットごとの操作を実行します。 ビットごとのAND、OR、およびXOR演算の真理値表は次のとおりです-

*link:/lisp/lisp_bitwise_operators [例を表示]*
p q p and q p or q p xor q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1
Assume if A = 60; and B = 13; now in binary format they will be as follows:
A = 0011 1100
B = 0000 1101
-----------------
A and B = 0000 1100
A or B = 0011 1101
A xor B = 0011 0001
not A  = 1100 0011

次の表に、LISPでサポートされているビット単位の演算子を示します。 変数 A が60を保持し、変数 B が13を保持すると仮定します-

Operator Description Example
logand This returns the bit-wise logical AND of its arguments. If no argument is given, then the result is -1, which is an identity for this operation. (logand a b)) will give 12
logior This returns the bit-wise logical INCLUSIVE OR of its arguments. If no argument is given, then the result is zero, which is an identity for this operation. (logior a b) will give 61
logxor This returns the bit-wise logical EXCLUSIVE OR of its arguments. If no argument is given, then the result is zero, which is an identity for this operation. (logxor a b) will give 49
lognor This returns the bit-wise NOT of its arguments. If no argument is given, then the result is -1, which is an identity for this operation. (lognor a b) will give -62,
logeqv This returns the bit-wise logical EQUIVALENCE (also known as exclusive nor) of its arguments. If no argument is given, then the result is -1, which is an identity for this operation. (logeqv a b) will give -50

LISP-意思決定

意思決定構造では、プログラマーが、プログラムによって評価またはテストされる1つ以上の条件を、条件が真であると判断された場合に実行されるステートメント、およびオプションで条件が実行された場合に実行される他のステートメントとともに指定する必要があります偽と判断されます。

以下は、ほとんどのプログラミング言語で見られる典型的な意思決定構造の一般的な形式です-

意思決定

LISPは、次のタイプの意思決定構造を提供します。 詳細を確認するには、次のリンクをクリックしてください。

Sr.No. Construct & Description
1

cond

このコンストラクトは、複数のテストアクション句のチェックに使用されます。 他のプログラミング言語のネストされたifステートメントと比較できます。

2

if

if構造にはさまざまな形式があります。 最も単純な形式では、テスト句、テストアクション、およびその他の結果アクションが続きます。 test句がtrueと評価されると、テストアクションが実行されます。それ以外の場合、結果句が評価されます。

3

when

最も単純な形式では、テスト句とテストアクションが後に続きます。 test句がtrueと評価されると、テストアクションが実行されます。それ以外の場合、結果句が評価されます。

4

case

この構造は、cond構造のような複数のtest-action句を実装します。 ただし、キーフォームを評価し、そのキーフォームの評価に基づいて複数のアクション句を許可します。

LISP-ループ

コードのブロックを何度も実行する必要がある場合があります。 ループステートメントを使用すると、ステートメントまたはステートメントのグループを複数回実行できます。ほとんどのプログラミング言語では、以下がループステートメントの一般的な形式です。

ループ

LISPは、ループ要件を処理するために次のタイプの構造を提供します。 詳細を確認するには、次のリンクをクリックしてください。

Sr.No. Construct & Description
1

loop

  • loop* コンストラクトは、LISPが提供する最も単純な反復形式です。 最も単純な形式では、 *return* ステートメントが見つかるまで、いくつかのステートメントを繰り返し実行できます。
2

loop for

ループの構成により、他の言語で最も一般的な反復のようなforループを実装できます。

3

do

doコンストラクトは、LISPを使用して反復を実行するためにも使用されます。 反復の構造化された形式を提供します。

4

dotimes

dotimesコンストラクトにより、一定の反復回数のループが可能になります。

5

dolist

dolistコンストラクトにより、リストの各要素を反復処理できます。

ブロックを正常に終了する

*block* および *return-from* を使用すると、エラーが発生した場合にネストされたブロックを正常に終了できます。
*block* 関数を使用すると、0個以上のステートメントで構成される本体を持つ名前付きブロックを作成できます。 構文は-
(block block-name(
...
...
))
*return-from* 関数は、ブロック名とオプション(デフォルトはnil)の戻り値を取ります。

次の例はこれを示しています-

main.lispという名前の新しいソースコードファイルを作成し、その中に次のコードを入力します-

(defun demo-function (flag)
   (print 'entering-outer-block)

   (block outer-block
      (print 'entering-inner-block)
      (print (block inner-block

         (if flag
            (return-from outer-block 3)
            (return-from inner-block 5)
         )

         (print 'This-wil--not-be-printed))
      )

      (print 'left-inner-block)
      (print 'leaving-outer-block)
   t)
)
(demo-function t)
(terpri)
(demo-function nil)

実行ボタンをクリックするか、Ctrl + Eを入力すると、LISPはすぐに実行し、返される結果は-

ENTERING-OUTER-BLOCK
ENTERING-INNER-BLOCK

ENTERING-OUTER-BLOCK
ENTERING-INNER-BLOCK
5
LEFT-INNER-BLOCK
LEAVING-OUTER-BLOCK

LISP-機能

関数は、一緒にタスクを実行するステートメントのグループです。

コードを別々の機能に分割できます。 コードを異なる関数に分割する方法はユーザー次第ですが、論理的には通常、各関数が特定のタスクを実行するように分割されます。

LISPでの関数の定義

*defun* という名前のマクロは、関数の定義に使用されます。 *defun* マクロには3つの引数が必要です-
  • 機能名
  • 関数のパラメーター
  • 関数の本体

defunの構文は-

(defun name (parameter-list) "Optional documentation string." body)

簡単な例で概念を説明しましょう。

例1

4つの数値の平均を出力する_averagenum_という名前の関数を作成してみましょう。 これらの数値をパラメーターとして送信します。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defun averagenum (n1 n2 n3 n4)
   (/( + n1 n2 n3 n4) 4)
)
(write(averagenum 10 20 30 40))

あなたがコードを実行すると、それは次の結果を返します-

25

例2

円の半径が引数として与えられたときに円の面積を計算する関数を定義して呼び出しましょう。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defun area-circle(rad)
   "Calculates area of a circle with given radius"
   (terpri)
   (format t "Radius: ~5f" rad)
   (format t "~%Area: ~10f" (* 3.141592 rad rad))
)
(area-circle 10)

あなたがコードを実行すると、それは次の結果を返します-

Radius:  10.0
Area:   314.1592

次のことに注意してください-

  • パラメーターとして空のリストを指定できます。つまり、関数は引数をとらず、リストは空で、()と記述されます。
  • LISPでは、オプションの引数、複数の引数、およびキーワードの引数も使用できます。
  • ドキュメント文字列は、関数の目的を説明しています。 これは関数の名前に関連付けられており、 documentation 関数を使用して取得できます。
  • 関数の本体は、任意の数のLisp式で構成できます。
  • 本体の最後の式の値は、関数の値として返されます。
  • return-from 特殊演算子を使用して、関数から値を返すこともできます。

上記の概念について簡単に説明します。 詳細を見つけるために次のリンクをクリックしてください-

  • リンク:/lisp/lisp_optional_parameters [オプションパラメータ]
  • リンク:/lisp/lisp_rest_parameters [残りのパラメーター]
  • リンク:/lisp/lisp_keyword_parameters [キーワードパラメータ]
  • リンク:/lisp/lisp_returning_values_functions [関数から値を返す]
  • リンク:/lisp/lisp_lambda_functions [ラムダ関数]
  • リンク:/lisp/lisp_mapping_functions [マッピング関数]

LISP-述語

述語は、特定の条件について引数をテストし、条件がfalseの場合、またはnil以外の値が条件がtrueの場合にnilを返す関数です。

次の表は、最も一般的に使用される述語のいくつかを示しています-

Sr.No. Predicate & Description
1

atom

1つの引数を取り、引数がアトムの場合はtを返し、そうでない場合はnilを返します。

2

equal

2つの引数を取り、それらが構造的に等しい場合は t を返し、そうでない場合は nil を返します。

3

eq

2つの引数を取り、同じメモリ位置を共有する同じオブジェクトである場合は t を返し、そうでない場合は nil を返します。

4

eql

2つの引数を取り、引数が eq であるか、同じ値の同じ型の数であるか、同じ文字を表す文字オブジェクトであるか、そうでない場合は nil の場合、 t を返します。

5

evenp

1つの数値引数を取り、引数が偶数の場合は t を返し、そうでない場合は nil を返します。

6

oddp

1つの数値引数を取り、引数が奇数の場合は t を返し、そうでない場合は nil を返します。

7

zerop

1つの数値引数を取り、引数がゼロの場合は t を返し、そうでない場合は nil を返します。

8

null

1つの引数を取り、引数の評価がnilの場合は t を返し、それ以外の場合は nil を返します。

9

listp

1つの引数を取り、引数がリストに評価される場合は t を返し、そうでない場合は nil を返します。

10

greaterp

1つ以上の引数を取り、単一の引数がある場合、または引数が左から右に連続して大きい場合は t を返し、そうでない場合は nil を返します。

11

lessp

1つ以上の引数を取り、単一の引数がある場合、または引数が左から右に連続して小さい場合は t を返し、そうでない場合は nil を返します。

12

numberp

1つの引数を取り、引数が数値の場合は t を返し、そうでない場合は nil を返します。

13

symbolp

1つの引数を取り、引数がシンボルの場合は t を返し、それ以外の場合は nil を返します。

14

integerp

1つの引数を取り、引数が整数の場合は t を返し、それ以外の場合は nil を返します。

15

rationalp

1つの引数を取り、引数が有理数(比率または数値)の場合は t を返し、それ以外の場合は nil を返します。

16

floatp

1つの引数を取り、引数が浮動小数点数の場合は t を返し、それ以外の場合は nil を返します。

17

realp

1つの引数を取り、引数が実数の場合は t を返し、それ以外の場合は nil を返します。

18

complexp

1つの引数を取り、引数が複素数の場合は t を返します。それ以外の場合は* nil。*を返します

19

characterp

1つの引数を取り、引数が文字の場合は t を返し、それ以外の場合は nil を返します。

20

stringp

1つの引数を取り、引数が文字列オブジェクトの場合は t を返します。それ以外の場合は nil を返します。

21

arrayp

1つの引数を取り、引数が配列オブジェクトの場合は t を返し、そうでない場合は nil を返します。

22

packagep

1つの引数を取り、引数がパッケージの場合は t を返します。それ以外の場合は* nil。*を返します

例1

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (atom 'abcd))
(terpri)
(write (equal 'a 'b))
(terpri)
(write (evenp 10))
(terpri)
(write (evenp 7 ))
(terpri)
(write (oddp 7 ))
(terpri)
(write (zerop 0.0000000001))
(terpri)
(write (eq 3 3.0 ))
(terpri)
(write (equal 3 3.0 ))
(terpri)
(write (null nil ))

あなたがコードを実行すると、それは次の結果を返します-

T
NIL
T
NIL
T
NIL
NIL
NIL
T

例2

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defun factorial (num)
   (cond ((zerop num) 1)
      (t ( * num (factorial (- num 1))))
   )
)
(setq n 6)
(format t "~% Factorial ~d is: ~d" n (factorial n))

あなたがコードを実行すると、それは次の結果を返します-

Factorial 6 is: 720

LISP-数字

Common Lispは、いくつかの種類の数値を定義します。 number データタイプには、LISPでサポートされるさまざまな種類の数値が含まれます。

LISPでサポートされている番号タイプは-

  • 整数
  • 比率
  • 浮動小数点数 *複素数

次の図は、LISPで使用可能な番号階層とさまざまな数値データ型を示しています-

数値型

LISPのさまざまな数値タイプ

次の表は、LISPで利用可能なさまざまな数値型データを示しています-

Sr.No. Data type & Description
1
  • fixnum*

このデータ型は、大きすぎず、主に-215〜215-1の範囲の整数を表します(マシンに依存)

2

bignum

これらは、LISPに割り当てられたメモリの量によってサイズが制限される非常に大きな数値であり、fixnumの数値ではありません。

3

ratio

分子/分母形式の2つの数値の比率を表します。/関数は、引数が整数の場合、常に結果を比率で生成します。

4

float

非整数の数値を表します。 精度が向上する4つのfloatデータ型があります。

5

complex

  1. cで示される複素数を表します。 実数部と虚数部は、有理数でも浮動小数点数でもかまいません。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (/1 2))
(terpri)
(write ( + (/1 2) (/3 4)))
(terpri)
(write ( + #c( 1 2) #c( 3 -4)))

あなたがコードを実行すると、それは次の結果を返します-

1/2
5/4
#C(4 -2)

数字関数

次の表は、いくつかの一般的に使用される数値関数を説明しています-

Sr.No. Function & Description
1

+, -, *,/

それぞれの算術演算

2

sin, cos, tan, acos, asin, atan

それぞれの三角関数。

3

sinh, cosh, tanh, acosh, asinh, atanh

それぞれの双曲線関数。

4

exp

べき乗関数。 e ^ x ^を計算します

5

expt

指数関数は、ベースとパワーの両方を取ります。

6

sqrt

数値の平方根を計算します。

7

log

対数関数。 1つのパラメーターが与えられた後、自然対数を計算します。それ以外の場合、2番目のパラメーターがベースとして使用されます。

8

conjugate

数値の複素共役を計算します。 実数の場合、数値自体を返します。

9

abs

数値の絶対値(または大きさ)を返します。

10

gcd

指定された数値の最大公約数を計算します。

11

lcm

指定された数値の最小公倍数を計算します。

12

isqrt

指定された自然数の正確な平方根以下の最大整数を提供します。

13

floor, ceiling, truncate, round

これらの関数はすべて、2つの引数を数値として受け取り、商を返します。 floor はratioより大きくない最大の整数を返します。 ceiling はratioよりも小さい小さい整数を選択します。そして、 round はratioに最も近い整数を選択します。

14

ffloor, fceiling, ftruncate, fround

上記と同じですが、商を浮動小数点数として返します。

15

mod, rem

除算の剰余を返します。

16

float

実数を浮動小数点数に変換します。

17

rational, rationalize

実数を有理数に変換します。

18

numerator, denominator

有理数のそれぞれの部分を返します。

19

realpart, imagpart

複素数の実数部と虚数部を返します。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (/45 78))
(terpri)
(write (floor 45 78))
(terpri)
(write (/3456 75))
(terpri)
(write (floor 3456 75))
(terpri)
(write (ceiling 3456 75))
(terpri)
(write (truncate 3456 75))
(terpri)
(write (round 3456 75))
(terpri)
(write (ffloor 3456 75))
(terpri)
(write (fceiling 3456 75))
(terpri)
(write (ftruncate 3456 75))
(terpri)
(write (fround 3456 75))
(terpri)
(write (mod 3456 75))
(terpri)
(setq c (complex 6 7))
(write c)
(terpri)
(write (complex 5 -9))
(terpri)
(write (realpart c))
(terpri)
(write (imagpart c))

あなたがコードを実行すると、それは次の結果を返します-

15/26
0
1152/25
46
47
46
46
46.0
47.0
46.0
46.0
6
#C(6 7)
#C(5 -9)
6
7

LISP-キャラクター

LISPでは、文字は* character。*型のデータオブジェクトとして表されます。

文字自体の前に#\の前にある文字オブジェクトを示すことができます。 たとえば、#\ aは文字aを意味します。

スペースおよびその他の特殊文字は、文字の名前の前に#\を付けることで示すことができます。 たとえば、#\ SPACEはスペース文字を表します。

次の例はこれを示しています-

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write 'a)
(terpri)
(write #\a)
(terpri)
(write-char #\a)
(terpri)
(write-char 'a)

あなたがコードを実行すると、それは次の結果を返します-

A
#\a
a
*** - WRITE-CHAR: argument A is not a character

特殊文字

Common LISPでは、コードで次の特殊文字を使用できます。 それらは準標準文字と呼ばれます。

  • #\ Backspace
  • #\タブ
  • #\改行
  • #\ページ
  • #\ Return
  • #\ Rubout

文字比較関数

<および>などの数値比較関数および演算子は、文字に対して機能しません。 Common LISPは、コード内の文字を比較するための他の2つの関数セットを提供します。

1つのセットは大文字と小文字を区別し、もう1つのセットは大文字と小文字を区別しません。

次の表は、機能を提供します-

Case Sensitive Functions Case-insensitive Functions Description
char= char-equal Checks if the values of the operands are all equal or not, if yes then condition becomes true.
char/= char-not-equal Checks if the values of the operands are all different or not, if values are not equal then condition becomes true.
char< char-lessp Checks if the values of the operands are monotonically decreasing.
char> char-greaterp Checks if the values of the operands are monotonically increasing.
char⇐ char-not-greaterp Checks if the value of any left operand is greater than or equal to the value of next right operand, if yes then condition becomes true.
char>= char-not-lessp Checks if the value of any left operand is less than or equal to the value of its right operand, if yes then condition becomes true.

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

; case-sensitive comparison
(write (char= #\a #\b))
(terpri)
(write (char= #\a #\a))
(terpri)
(write (char= #\a #\A))
(terpri)

;case-insensitive comparision
(write (char-equal #\a #\A))
(terpri)
(write (char-equal #\a #\b))
(terpri)
(write (char-lessp #\a #\b #\c))
(terpri)
(write (char-greaterp #\a #\b #\c))

あなたがコードを実行すると、それは次の結果を返します-

NIL
T
NIL
T
NIL
T
NIL

LISP-配列

LISPでは、 make-array 関数を使用して、単一または複数次元の配列を定義できます。 配列は、任意のLISPオブジェクトを要素として保存できます。

すべての配列は、連続したメモリ位置で構成されています。 最下位アドレスは最初の要素に対応し、最上位アドレスは最後の要素に対応します。

ランク

配列の次元数は、ランクと呼ばれます。

LISPでは、配列要素は非負の整数インデックスのシーケンスによって指定されます。 シーケンスの長さは、配列のランクと等しくなければなりません。 インデックスはゼロから始まります。

たとえば、my-arrayという名前の10セルの配列を作成するには、次のように記述できます-

(setf my-array (make-array '(10)))

aref関数を使用すると、セルのコンテンツにアクセスできます。 配列の名前とインデックス値の2つの引数を取ります。

たとえば、10番目のセルのコンテンツにアクセスするには、次のように記述します-

(aref my-array 9)

例1

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (setf my-array (make-array '(10))))
(terpri)
(setf (aref my-array 0) 25)
(setf (aref my-array 1) 23)
(setf (aref my-array 2) 45)
(setf (aref my-array 3) 10)
(setf (aref my-array 4) 20)
(setf (aref my-array 5) 17)
(setf (aref my-array 6) 25)
(setf (aref my-array 7) 19)
(setf (aref my-array 8) 67)
(setf (aref my-array 9) 30)
(write my-array)

あなたがコードを実行すると、それは次の結果を返します-

#(NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL)
#(25 23 45 10 20 17 25 19 67 30)

例2

3行3列の配列を作成しましょう。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setf x (make-array '(3 3)
   :initial-contents '((0 1 2 ) (3 4 5) (6 7 8)))
)
(write x)

あなたがコードを実行すると、それは次の結果を返します-

#2A((0 1 2) (3 4 5) (6 7 8))

実施例3

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq a (make-array '(4 3)))
(dotimes (i 4)
   (dotimes (j 3)
      (setf (aref a i j) (list i 'x j '= ( *i j)))
   )
)
(dotimes (i 4)
   (dotimes (j 3)
      (print (aref a i j))
   )
)

あなたがコードを実行すると、それは次の結果を返します-

(0 X 0 = 0)
(0 X 1 = 0)
(0 X 2 = 0)
(1 X 0 = 0)
(1 X 1 = 1)
(1 X 2 = 2)
(2 X 0 = 0)
(2 X 1 = 2)
(2 X 2 = 4)
(3 X 0 = 0)
(3 X 1 = 3)
(3 X 2 = 6)

make-array関数の完全な構文

make-array関数は、他の多くの引数を取ります。 この関数の完全な構文を見てみましょう-

make-array dimensions :element-type :initial-element :initial-contents :adjustable :fill-pointer  :displaced-to :displaced-index-offset

_dimensions_引数を除き、他のすべての引数はキーワードです。 次の表に、引数の簡単な説明を示します。

Sr.No. Argument & Description
1
  • dimensions*

配列の次元を提供します。 これは、1次元配列の数であり、多次元配列のリストです。

2

:element-type

これは型指定子であり、デフォルト値はTです。 いかなるタイプ

3

:initial-element

初期要素の値。 すべての要素が特定の値に初期化された配列を作成します。

4

:initial-content

オブジェクトとしての初期コンテンツ。

5

:adjustable

基になるメモリのサイズを変更できるサイズ変更可能な(または調整可能な)ベクトルを作成するのに役立ちます。 引数は、配列が調整可能かどうかを示すブール値で、デフォルト値はNILです。

6

:fill-pointer

サイズ変更可能なベクターに実際に保存されている要素の数を追跡します。

7

:displaced-to

これは、指定された配列と内容を共有する、置き換えられた配列または共有配列の作成に役立ちます。 両方の配列の要素タイプは同じである必要があります。 :displaced-toオプションは、:initial-elementまたは:initial-contentsオプションと一緒に使用することはできません。 この引数のデフォルトはnilです。

8

:displaced-index-offset

作成された共有配列のインデックスオフセットを提供します。

実施例4

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq myarray (make-array '(3 2 3)
   :initial-contents
   '(((a b c) (1 2 3))
      ((d e f) (4 5 6))
      ((g h i) (7 8 9))
   ))
)
(setq array2 (make-array 4 :displaced-to myarray :displaced-index-offset 2))
(write myarray)
(terpri)
(write array2)

あなたがコードを実行すると、それは次の結果を返します-

#3A(((A B C) (1 2 3)) ((D E F) (4 5 6)) ((G H I) (7 8 9)))
#(C 1 2 3)

変位した配列が二次元である場合-

(setq myarray (make-array '(3 2 3)
   :initial-contents
   '(((a b c) (1 2 3))
      ((d e f) (4 5 6))
      ((g h i) (7 8 9))
   ))
)
(setq array2 (make-array '(3 2) :displaced-to myarray :displaced-index-offset 2))
(write myarray)
(terpri)
(write array2)

あなたがコードを実行すると、それは次の結果を返します-

#3A(((A B C) (1 2 3)) ((D E F) (4 5 6)) ((G H I) (7 8 9)))
#2A((C 1) (2 3) (D E))

変位したインデックスオフセットを5に変更してみましょう-

(setq myarray (make-array '(3 2 3)
   :initial-contents
   '(((a b c) (1 2 3))
      ((d e f) (4 5 6))
      ((g h i) (7 8 9))
   ))
)
(setq array2 (make-array '(3 2) :displaced-to myarray :displaced-index-offset 5))
(write myarray)
(terpri)
(write array2)

あなたがコードを実行すると、それは次の結果を返します-

#3A(((A B C) (1 2 3)) ((D E F) (4 5 6)) ((G H I) (7 8 9)))
#2A((3 D) (E F) (4 5))

実施例5

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

;a one dimensional array with 5 elements,
;initail value 5
(write (make-array 5 :initial-element 5))
(terpri)

;two dimensional array, with initial element a
(write (make-array '(2 3) :initial-element 'a))
(terpri)

;an array of capacity 14, but fill pointer 5, is 5
(write(length (make-array 14 :fill-pointer 5)))
(terpri)

;however its length is 14
(write (array-dimensions (make-array 14 :fill-pointer 5)))
(terpri)

; a bit array with all initial elements set to 1
(write(make-array 10 :element-type 'bit :initial-element 1))
(terpri)

; a character array with all initial elements set to a
; is a string actually
(write(make-array 10 :element-type 'character :initial-element #\a))
(terpri)

; a two dimensional array with initial values a
(setq myarray (make-array '(2 2) :initial-element 'a :adjustable t))
(write myarray)
(terpri)

;readjusting the array
(adjust-array myarray '(1 3) :initial-element 'b)
(write myarray)

あなたがコードを実行すると、それは次の結果を返します-

#(5 5 5 5 5)
#2A((A A A) (A A A))
5
(14)
#*1111111111
"aaaaaaaaaa"
#2A((A A) (A A))
#2A((A A B))

LISP-文字列

Common Lispの文字列はベクトル、つまり文字の1次元配列です。

文字列リテラルは二重引用符で囲みます。 文字セットでサポートされている文字は、二重引用符( ")とエスケープ文字(\)を除き、二重引用符で囲んで文字列を作成できます。 ただし、これらをバックスラッシュ(\)でエスケープすることで含めることができます。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write-line "Hello World")
(write-line "Welcome to Tutorials Point")

;escaping the double quote character
(write-line "Welcome to \"Tutorials Point\"")

あなたがコードを実行すると、それは次の結果を返します-

Hello World
Welcome to Tutorials Point
Welcome to "Tutorials Point"

文字列比較関数

<および>などの数値比較関数および演算子は、文字列では機能しません。 Common LISPは、コード内の文字列を比較するための他の2つの関数セットを提供します。 1つのセットは大文字と小文字を区別し、もう1つのセットは大文字と小文字を区別しません。

次の表は、機能を提供します-

Case Sensitive Functions Case-insensitive Functions Description
string= string-equal Checks if the values of the operands are all equal or not, if yes then condition becomes true.
string/= string-not-equal Checks if the values of the operands are all different or not, if values are not equal then condition becomes true.
string< string-lessp Checks if the values of the operands are monotonically decreasing.
string> string-greaterp Checks if the values of the operands are monotonically increasing.
string⇐ string-not-greaterp Checks if the value of any left operand is greater than or equal to the value of next right operand, if yes then condition becomes true.
string>= string-not-lessp Checks if the value of any left operand is less than or equal to the value of its right operand, if yes then condition becomes true.

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

; case-sensitive comparison
(write (string= "this is test" "This is test"))
(terpri)
(write (string> "this is test" "This is test"))
(terpri)
(write (string< "this is test" "This is test"))
(terpri)

;case-insensitive comparision
(write (string-equal "this is test" "This is test"))
(terpri)
(write (string-greaterp "this is test" "This is test"))
(terpri)
(write (string-lessp "this is test" "This is test"))
(terpri)

;checking non-equal
(write (string/= "this is test" "this is Test"))
(terpri)
(write (string-not-equal "this is test" "This is test"))
(terpri)
(write (string/= "lisp" "lisping"))
(terpri)
(write (string/= "decent" "decency"))

あなたがコードを実行すると、それは次の結果を返します-

NIL
0
NIL
T
NIL
NIL
8
NIL
4
5

ケース制御機能

次の表は、ケース制御機能について説明しています-

Sr.No. Function & Description
1

string-upcase

文字列を大文字に変換します

2

string-downcase

文字列を小文字に変換します

3

string-capitalize

文字列の各単語を大文字にします

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write-line (string-upcase "a big hello from tutorials point"))
(write-line (string-capitalize "a big hello from tutorials point"))

あなたがコードを実行すると、それは次の結果を返します-

A BIG HELLO FROM TUTORIALS POINT
A Big Hello From Tutorials Point

ストリングのトリミング

次の表では、文字列のトリミング機能について説明します-

Sr.No. Function & Description
1

string-trim

最初の引数として文字列を、2番目の引数として文字列を取り、最初の引数にあるすべての文字が引数文字列から削除された部分文字列を返します。

2

String-left-trim

最初の引数として文字列を、2番目の引数として文字列を取り、最初の引数にあるすべての文字が引数文字列の先頭から削除された部分文字列を返します。

3

String-right-trim

最初の引数として文字列文字を、2番目の引数として文字列を取り、最初の引数にあるすべての文字が引数文字列の末尾から削除された部分文字列を返します。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write-line (string-trim " " "   a big hello from tutorials point   "))
(write-line (string-left-trim " " "   a big hello from tutorials point   "))
(write-line (string-right-trim " " "   a big hello from tutorials point   "))
(write-line (string-trim " a" "   a big hello from tutorials point   "))

あなたがコードを実行すると、それは次の結果を返します-

a big hello from tutorials point
a big hello from tutorials point
   a big hello from tutorials point
big hello from tutorials point

その他の文字列関数

LISPの文字列は配列であるため、シーケンスでもあります。 これらのデータ型については、今後のチュートリアルで説明します。 配列およびシーケンスに適用可能なすべての関数は、文字列にも適用されます。 ただし、さまざまな例を使用して、一般的に使用されるいくつかの機能を示します。

長さの計算

*length* 関数は、文字列の長さを計算します。

部分文字列の抽出

*subseq* 関数は、特定のインデックスで始まり、特定の終了インデックスまたは文字列の終わりまで続く部分文字列を返します(文字列はシーケンスでもあるため)。

文字列内の文字へのアクセス

*char* 関数を使用すると、文字列の個々の文字にアクセスできます。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (length "Hello World"))
(terpri)
(write-line (subseq "Hello World" 6))
(write (char "Hello World" 6))

あなたがコードを実行すると、それは次の結果を返します-

11
World
#\W

文字列のソートとマージ

*sort* 関数を使用すると、文字列をソートできます。 シーケンス(ベクトルまたは文字列)と2つの引数の述語を取り、ソートされたバージョンのシーケンスを返します。
*merge* 関数は2つのシーケンスと1つの述語を取り、述語に従って2つのシーケンスをマージして生成されたシーケンスを返します。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

;sorting the strings
(write (sort (vector "Amal" "Akbar" "Anthony") #'string<))
(terpri)

;merging the strings
(write (merge 'vector (vector "Rishi" "Zara" "Priyanka")
   (vector "Anju" "Anuj" "Avni") #'string<))

あなたがコードを実行すると、それは次の結果を返します-

#("Akbar" "Amal" "Anthony")
#("Anju" "Anuj" "Avni" "Rishi" "Zara" "Priyanka")

文字列の反転

*reverse* 関数は文字列を反転します。

たとえば、main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write-line (reverse "Are we not drawn onward, we few, drawn onward to new era"))

あなたがコードを実行すると、それは次の結果を返します-

are wen ot drawno nward ,wef ew ,drawno nward ton ew erA

文字列の連結

concatenate関数は、2つの文字列を連結します。 これは汎用シーケンス関数であり、最初の引数として結果タイプを提供する必要があります。

たとえば、main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write-line (concatenate 'string "Are we not drawn onward, " "we few, drawn onward to new era"))

あなたがコードを実行すると、それは次の結果を返します-

Are we not drawn onward, we few, drawn onward to new era

LISP-シーケンス

シーケンスは、LISPの抽象データ型です。 ベクターとリストは、このデータ型の2つの具体的なサブタイプです。 シーケンスデータタイプで定義されたすべての機能は、実際にはすべてのベクトルおよびリストタイプに適用されます。

このセクションでは、シーケンスで最も一般的に使用される関数について説明します。

シーケンス(ベクターやリストなど)を操作するさまざまな方法を開始する前に、使用可能なすべての関数のリストを見てみましょう。

シーケンスを作成する

関数make-sequenceを使用すると、任意のタイプのシーケンスを作成できます。 この関数の構文は次のとおりです-

make-sequence sqtype sqsize &key :initial-element

タイプ_sqtype_および長さ_sqsize._のシーケンスを作成します

オプションで、_:initial-element_引数を使用して値を指定することもできます。その場合、各要素はこの値に初期化されます。

たとえば、main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (make-sequence '(vector float)
   10
   :initial-element 1.0))

あなたがコードを実行すると、それは次の結果を返します-

#(1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0)

シーケンスの汎用関数

Sr.No. Function & Description
1

elt

整数インデックスを介して個々の要素にアクセスできます。

2

length

シーケンスの長さを返します。

3

subseq

特定のインデックスで始まり、特定の終了インデックスまたはシーケンスの終わりまで続くサブシーケンスを抽出することにより、サブシーケンスを返します。

4

copy-seq

引数と同じ要素を含むシーケンスを返します。

5

fill

シーケンスの複数の要素を単一の値に設定するために使用されます。

6

replace

2つのシーケンスを取り、最初の引数シーケンスは、2番目の引数シーケンスから連続した要素をコピーすることにより破壊的に変更されます。

7

count

アイテムとシーケンスを受け取り、アイテムがシーケンスに表示される回数を返します。

8

reverse

引数の同じ要素を逆順で含むシーケンスを返します。

9

nreverse

シーケンスと同じ要素を含む同じシーケンスを逆順で返します。

10

concatenate

任意の数のシーケンスの連結を含む新しいシーケンスを作成します。

11

position

アイテムとシーケンスを受け取り、シーケンス内のアイテムのインデックスまたはnilを返します。

12

find

アイテムとシーケンスが必要です。 シーケンス内のアイテムを見つけて返し、見つからない場合はnilを返します。

13

sort

シーケンスと2つの引数の述語を取り、シーケンスのソートされたバージョンを返します。

14

merge

2つのシーケンスと1つの述語を取り、述語に従って2つのシーケンスをマージして生成されたシーケンスを返します。

15

map

n引数の関数とn個のシーケンスを受け取り、関数をシーケンスの後続の要素に適用した結果を含む新しいシーケンスを返します。

16

some

述語を引数として受け取り、引数シーケンスを反復処理し、述語によって返される最初の非NIL値を返すか、述語が満たされない場合はfalseを返します。

17

every

述語を引数として受け取り、引数シーケンスを反復処理し、述語が失敗するとすぐに終了し、falseを返します。 述語が常に満たされる場合、trueを返します。

18

notany

述語を引数として受け取り、引数シーケンスを反復処理し、述語が満たされるとすぐにfalseを返し、満たされない場合はtrueを返します。

19

notevery

述語を引数として受け取り、引数シーケンスを反復処理し、述語が失敗するとすぐにtrueを返し、述語が常に満たされる場合はfalseを返します。

20

reduce

単一のシーケンスにマッピングし、最初にシーケンスの最初の2つの要素に2引数関数を適用し、次に関数とシーケンスの後続の要素によって返される値に適用します。

21

search

シーケンスを検索して、テストを満たす1つ以上の要素を見つけます。

22

remove

アイテムとシーケンスを受け取り、アイテムのインスタンスが削除されたシーケンスを返します。

23

delete

これもアイテムとシーケンスを取り、アイテムを除いて同じ要素を持つ引数シーケンスと同じ種類のシーケンスを返します。

24

substitute

新しいアイテム、既存のアイテム、およびシーケンスを受け取り、既存のアイテムのインスタンスが新しいアイテムに置き換えられたシーケンスを返します。

25

nsubstitute

新しいアイテム、既存のアイテム、およびシーケンスを受け取り、既存のアイテムのインスタンスが新しいアイテムに置き換えられた同じシーケンスを返します。

26

mismatch

2つのシーケンスを取り、不一致の要素の最初のペアのインデックスを返します。

標準シーケンス関数のキーワード引数

Argument Meaning Default Value
:test It is a two-argument function used to compare item (or value extracted by :key function) to element. EQL
:key One-argument function to extract key value from actual sequence element. NIL means use element as is. NIL
:start Starting index (inclusive) of subsequence. 0
:end Ending index (exclusive) of subsequence. NIL indicates end of sequence. NIL
:from-end If true, the sequence will be traversed in reverse order, from end to start. NIL
:count Number indicating the number of elements to remove or substitute or NIL to indicate all (REMOVE and SUBSTITUTE only). NIL

シーケンスで動作するこれらの関数の引数として使用されるさまざまな関数とキーワードについて説明しました。 次のセクションでは、例を使用してこれらの関数を使用する方法を説明します。

長さと要素を見つける

*length* 関数はシーケンスの長さを返し、 *elt* 関数を使用すると、整数インデックスを使用して個々の要素にアクセスできます。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq x (vector 'a 'b 'c 'd 'e))
(write (length x))
(terpri)
(write (elt x 3))

あなたがコードを実行すると、それは次の結果を返します-

5
D

シーケンスの変更

一部のシーケンス関数を使用すると、シーケンスを繰り返し処理し、明示的なループを記述せずに特定の要素を検索、削除、カウント、またはフィルタリングするなどの操作を実行できます。

次の例はこれを示しています-

例1

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (count 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (remove 5 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (delete 5 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (substitute 10 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (find 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (position 5 '(1 5 6 7 8 9 2 7 3 4 5)))

あなたがコードを実行すると、それは次の結果を返します-

2
(1 6 7 8 9 2 7 3 4)
(1 6 7 8 9 2 7 3 4)
(1 5 6 10 8 9 2 10 3 4 5)
7
1

例2

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (delete-if #'oddp '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (delete-if #'evenp '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (remove-if #'evenp '(1 5 6 7 8 9 2 7 3 4 5) :count 1 :from-end t))
(terpri)
(setq x (vector 'a 'b 'c 'd 'e 'f 'g))
(fill x 'p :start 1 :end 4)
(write x)

あなたがコードを実行すると、それは次の結果を返します-

(6 8 2 4)
(1 5 7 9 7 3 5)
(1 5 6 7 8 9 2 7 3 5)
#(A P P P E F G)

シーケンスのソートとマージ

ソート関数は、シーケンスと2つの引数の述語を取り、シーケンスのソートされたバージョンを返します。

例1

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (sort '(2 4 7 3 9 1 5 4 6 3 8) #'<))
(terpri)
(write (sort '(2 4 7 3 9 1 5 4 6 3 8) #'>))
(terpri)

あなたがコードを実行すると、それは次の結果を返します-

(1 2 3 3 4 4 5 6 7 8 9)
(9 8 7 6 5 4 4 3 3 2 1)

例2

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (merge 'vector #(1 3 5) #(2 4 6) #'<))
(terpri)
(write (merge 'list #(1 3 5) #(2 4 6) #'<))
(terpri)

あなたがコードを実行すると、それは次の結果を返します-

#(1 2 3 4 5 6)
(1 2 3 4 5 6)

シーケンス述語

関数every、some、notany、noteveryは、シーケンス述部と呼ばれます。

これらの関数はシーケンスを反復処理し、ブール述語をテストします。

これらの関数はすべて、最初の引数として述語を取り、残りの引数はシーケンスです。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (every #'evenp #(2 4 6 8 10)))
(terpri)
(write (some #'evenp #(2 4 6 8 10 13 14)))
(terpri)
(write (every #'evenp #(2 4 6 8 10 13 14)))
(terpri)
(write (notany #'evenp #(2 4 6 8 10)))
(terpri)
(write (notevery #'evenp #(2 4 6 8 10 13 14)))
(terpri)

あなたがコードを実行すると、それは次の結果を返します-

T
T
NIL
NIL
T

マッピングシーケンス

マッピング関数についてはすでに説明しました。 同様に、 map 関数を使用すると、1つ以上のシーケンスの後続の要素に関数を適用できます。

*map* 関数は、n引数の関数とn個のシーケンスを取り、シーケンスの後続の要素に関数を適用した後、新しいシーケンスを返します。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (map 'vector #'* #(2 3 4 5) #(3 5 4 8)))

あなたがコードを実行すると、それは次の結果を返します-

#(6 15 16 40)

LISP-リスト

リストは、従来のLISPで最も重要かつ主要な複合データ構造でした。 現在のCommon LISPは、ベクター、ハッシュテーブル、クラス、または構造などの他のデータ構造を提供します。

リストは、単一のリンクリストです。 LISPでは、リストは一緒にリンクされた cons という名前の単純なレコード構造のチェーンとして構築されます。

短所レコード構造

*cons* は、 *car* および* cdr。*と呼ばれる2つのコンポーネントを含むレコード構造です。

コンスセルまたはコンスオブジェクトは、関数* cons。*を使用して作成される値のペアです。

*cons* 関数は2つの引数を取り、2つの値を含む新しいconsセルを返します。 これらの値は、あらゆる種類のオブジェクトへの参照になります。

2番目の値がnilまたは別のコンスセルでない場合、値は括弧で囲まれたドットペアとして出力されます。

コンスセルの2つの値は、 car および* cdr。と呼ばれます。 *car 関数は、最初の値にアクセスするために使用され、 cdr 関数は、2番目の値にアクセスするために使用されます。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (cons 1 2))
(terpri)
(write (cons 'a 'b))
(terpri)
(write (cons 1 nil))
(terpri)
(write (cons 1 (cons 2 nil)))
(terpri)
(write (cons 1 (cons 2 (cons 3 nil))))
(terpri)
(write (cons 'a (cons 'b (cons 'c nil))))
(terpri)
(write ( car (cons 'a (cons 'b (cons 'c nil)))))
(terpri)
(write ( cdr (cons 'a (cons 'b (cons 'c nil)))))

あなたがコードを実行すると、それは次の結果を返します-

(1 . 2)
(A . B)
(1)
(1 2)
(1 2 3)
(A B C)
A
(B C)

上記の例は、コンス構造を使用して単一のリンクリストを作成する方法を示しています。たとえば、リスト(A B C)は、_cdrs_でリンクされた3つのコンスセルで構成されています。

概略的に、それは次のように表現できます-

LISPのリスト

コンスセルを使用してリストを作成できますが、ネストされた cons 関数呼び出しからリストを作成することは最良の解決策にはなりません。 list 関数は、LISPでリストを作成するために使用されます。

リスト関数は任意の数の引数を取ることができ、関数であるため、引数を評価します。

*first* および *rest* 関数は、リストの最初の要素と残りの部分を提供します。 次の例は、概念を示しています。

例1

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (list 1 2))
(terpri)
(write (list 'a 'b))
(terpri)
(write (list 1 nil))
(terpri)
(write (list 1 2 3))
(terpri)
(write (list 'a 'b 'c))
(terpri)
(write (list 3 4 'a (car '(b . c)) ( *4 -2)))
(terpri)
(write (list (list 'a 'b) (list 'c 'd 'e)))

あなたがコードを実行すると、それは次の結果を返します-

(1 2)
(A B)
(1 NIL)
(1 2 3)
(A B C)
(3 4 A B -8)
((A B) (C D E))

例2

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defun my-library (title author rating availability)
   (list :title title :author author :rating rating :availabilty availability)
)

(write (getf (my-library "Hunger Game" "Collins" 9 t) :title))

あなたがコードを実行すると、それは次の結果を返します-

"Hunger Game"

リスト操作関数

次の表に、一般的に使用されるリスト操作関数を示します。

Sr.No. Function & Description
1
  • car*

引数としてリストを取り、その最初の要素を返します。

2

cdr

引数としてリストを取り、最初の要素のないリストを返します

3

cons

要素とリストの2つの引数を取り、要素が最初に挿入されたリストを返します。

4

list

任意の数の引数を取り、引数をリストのメンバー要素として含むリストを返します。

5

append

2つ以上のリストを1つにマージします。

6

last

リストを受け取り、最後の要素を含むリストを返します。

7

member

最初の引数が2番目の引数のメンバーである場合、2番目の引数がリストでなければならない2つの引数を取り、最初の引数で始まるリストの残りを返します。

8

reverse

リストを取得し、上位要素を逆順に並べたリストを返します。

すべてのシーケンス機能はリストに適用できることに注意してください。

実施例3

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (car '(a b c d e f)))
(terpri)
(write (cdr '(a b c d e f)))
(terpri)
(write (cons 'a '(b c)))
(terpri)
(write (list 'a '(b c) '(e f)))
(terpri)
(write (append '(b c) '(e f) '(p q) '() '(g)))
(terpri)
(write (last '(a b c d (e f))))
(terpri)
(write (reverse '(a b c d (e f))))

あなたがコードを実行すると、それは次の結果を返します-

A
(B C D E F)
(A B C)
(A (B C) (E F))
(B C E F P Q G)
((E F))
((E F) D C B A)

carとcdr関数の連結

*car* および *cdr* 関数とそれらの組み合わせにより、リストの特定の要素/メンバーを抽出できます。

ただし、carおよびcdr関数のシーケンスは、文字cおよびr内のcarの文字aとcdrの文字dを連結することにより短縮できます。

たとえば、関数呼び出しのシーケンス-car cdr car cdrを短縮するためにcadadrを書くことができます。

したがって、(cadadr '(a(c d)(e f g)))はdを返します

実施例4

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (cadadr '(a (c d) (e f g))))
(terpri)
(write (caar (list (list 'a 'b) 'c)))
(terpri)
(write (cadr (list (list 1 2) (list 3 4))))
(terpri)

あなたがコードを実行すると、それは次の結果を返します-

D
A
(3 4)

LISP-シンボル

LISPでは、シンボルはデータオブジェクトを表す名前であり、興味深いことに、データオブジェクトでもあります。

シンボルを特別なものにしているのは、 property list または* plist。*というコンポーネントがあることです。

プロパティリスト

LISPでは、プロパティをシンボルに割り当てることができます。 たとえば、「person」オブジェクトがあるとします。 この「人物」オブジェクトには、名前、性別、身長、体重、住所、職業などのプロパティが必要です。 プロパティは属性名のようなものです。

プロパティリストは、偶数(おそらくゼロ)の要素を持つリストとして実装されます。 リスト内の要素の各ペアはエントリを構成します。最初の項目は*指標*で、2番目の項目は*値*です

シンボルが作成されると、そのプロパティリストは最初は空です。 プロパティは、 setf フォーム内で get を使用して作成されます。

たとえば、次のステートメントにより、プロパティのタイトル、作成者、発行者、およびそれぞれの値を(シンボル) 'book’という名前のオブジェクトに割り当てることができます。

例1

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (setf (get 'books'title) '(Gone with the Wind)))
(terpri)
(write (setf (get 'books 'author) '(Margaret Michel)))
(terpri)
(write (setf (get 'books 'publisher) '(Warner Books)))

あなたがコードを実行すると、それは次の結果を返します-

(GONE WITH THE WIND)
(MARGARET MICHEL)
(WARNER BOOKS)

さまざまなプロパティリスト関数を使用すると、プロパティを割り当てたり、シンボルのプロパティを取得、置換、削除したりできます。

*get* 関数は、指定されたインジケーターのシンボルのプロパティリストを返します。 次の構文があります-
get symbol indicator &optional default
*get* 関数は、指定されたインジケータの指定されたシンボルのプロパティリストを検索し、見つかった場合は対応する値を返します。それ以外の場合はデフォルトが返されます(デフォルト値が指定されていない場合はnil)。

例2

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setf (get 'books 'title) '(Gone with the Wind))
(setf (get 'books 'author) '(Margaret Micheal))
(setf (get 'books 'publisher) '(Warner Books))

(write (get 'books 'title))
(terpri)
(write (get 'books 'author))
(terpri)
(write (get 'books 'publisher))

あなたがコードを実行すると、それは次の結果を返します-

(GONE WITH THE WIND)
(MARGARET MICHEAL)
(WARNER BOOKS)
*symbol-plist* 関数を使用すると、シンボルのすべてのプロパティを表示できます。

実施例3

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setf (get 'annie 'age) 43)
(setf (get 'annie 'job) 'accountant)
(setf (get 'annie 'sex) 'female)
(setf (get 'annie 'children) 3)

(terpri)
(write (symbol-plist 'annie))

あなたがコードを実行すると、それは次の結果を返します-

(CHILDREN 3 SEX FEMALE JOB ACCOUNTANT AGE 43)
*remprop* 関数は、指定されたプロパティをシンボルから削除します。

実施例4

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setf (get 'annie 'age) 43)
(setf (get 'annie 'job) 'accountant)
(setf (get 'annie 'sex) 'female)
(setf (get 'annie 'children) 3)

(terpri)
(write (symbol-plist 'annie))
(remprop 'annie 'age)
(terpri)
(write (symbol-plist 'annie))

あなたがコードを実行すると、それは次の結果を返します-

(CHILDREN 3 SEX FEMALE JOB ACCOUNTANT AGE 43)
(CHILDREN 3 SEX FEMALE JOB ACCOUNTANT)

LISP-ベクトル

ベクトルは1次元配列であるため、配列のサブタイプです。 ベクターとリストは、まとめてシーケンスと呼ばれます。 したがって、これまでに説明したすべてのシーケンスジェネリック関数と配列関数は、ベクトルに作用します。

ベクターの作成

ベクトル関数を使用すると、特定の値を持つ固定サイズのベクトルを作成できます。 任意の数の引数を取り、それらの引数を含むベクトルを返します。

例1

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setf v1 (vector 1 2 3 4 5))
(setf v2 #(a b c d e))
(setf v3 (vector 'p 'q 'r 's 't))

(write v1)
(terpri)
(write v2)
(terpri)
(write v3)

あなたがコードを実行すると、それは次の結果を返します-

#(1 2 3 4 5)
#(A B C D E)
#(P Q R S T)

LISPは、ベクトルのリテラル表記として#(…​)構文を使用することに注意してください。 これを使用できます#(…​ )コードにリテラルベクトルを作成して含める構文。

ただし、これらはリテラルベクトルであるため、それらを変更することはLISPで定義されていません。 したがって、プログラミングの場合は、常に vector 関数、またはより一般的な関数 make-array を使用して、変更する予定のベクトルを作成する必要があります。

*make-array* 関数は、ベクターを作成するより一般的な方法です。 *aref* 関数を使用して、ベクトル要素にアクセスできます。

例2

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq a (make-array 5 :initial-element 0))
(setq b (make-array 5 :initial-element 2))

(dotimes (i 5)
   (setf (aref a i) i))

(write a)
(terpri)
(write b)
(terpri)

あなたがコードを実行すると、それは次の結果を返します-

#(0 1 2 3 4)
#(2 2 2 2 2)

塗りつぶしポインタ

*make-array* 関数を使用すると、サイズ変更可能なベクターを作成できます。

関数の fill-pointer 引数は、ベクターに実際に保存されている要素の数を追跡します。 要素をベクターに追加するときに埋められる次の位置のインデックスです。

*vector-push* 関数を使用すると、サイズ変更可能なベクターの末尾に要素を追加できます。 フィルポインタが1増加します。
*vector-pop* 関数は、最後にプッシュされたアイテムを返し、フィルポインターを1減らします。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq a (make-array 5 :fill-pointer 0))
(write a)

(vector-push 'a a)
(vector-push 'b a)
(vector-push 'c a)

(terpri)
(write a)
(terpri)

(vector-push 'd a)
(vector-push 'e a)

;this will not be entered as the vector limit is 5
(vector-push 'f a)

(write a)
(terpri)

(vector-pop a)
(vector-pop a)
(vector-pop a)

(write a)

あなたがコードを実行すると、それは次の結果を返します-

#()
#(A B C)
#(A B C D E)
#(A B)

ベクトルはシーケンスであり、すべてのシーケンス関数はベクトルに適用できます。 ベクトル関数については、シーケンスの章を参照してください。

LISP-セット

Common Lispは、セットデータ型を提供しません。 ただし、リストに対してセット操作を実行できる多くの機能を提供します。

さまざまな基準に基づいて、リスト内のアイテムを追加、削除、および検索できます。 ユニオン、インターセクション、セット差分などのさまざまなセット操作を実行することもできます。

LISPでのセットの実装

リストのようなセットは通常、コンスセルの観点から実装されます。 ただし、このまさに理由で、集合が大きくなるほど集合演算の効率は低下します。

*adjoin* 関数を使用すると、セットを作成できます。 アイテムとセットを表すリストを受け取り、そのアイテムと元のセット内のすべてのアイテムを含むセットを表すリストを返します。
*adjoin* 関数は、指定されたリスト内のアイテムを最初に検索し、見つかった場合は元のリストを返します。それ以外の場合は、 *car* をアイテムとして、 *cdr* が元のリストを指している新しいコンスセルを作成し、この新しいリストを返します。
*adjoin* 関数は、*:key *および*:test *キーワード引数も取ります。 これらの引数は、アイテムが元のリストに存在するかどうかを確認するために使用されます。

adjoin関数は元のリストを変更しないため、リスト自体に変更を加えるには、adjoinによって返される値を元のリストに割り当てるか、マクロ pushnew を使用してアイテムを追加する必要がありますセット。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

; creating myset as an empty list
(defparameter *myset *())
(adjoin 1* myset*)
(adjoin 2 *myset*)

; adjoin did not change the original set
;so it remains same
(write *myset*)
(terpri)
(setf *myset *(adjoin 1* myset*))
(setf *myset *(adjoin 2* myset*))

;now the original set is changed
(write *myset*)
(terpri)

;adding an existing value
(pushnew 2 *myset*)

;no duplicate allowed
(write *myset*)
(terpri)

;pushing a new value
(pushnew 3 *myset*)
(write *myset*)
(terpri)

あなたがコードを実行すると、それは次の結果を返します-

NIL
(2 1)
(2 1)
(3 2 1)

メンバーシップの確認

関数のメンバーグループを使用すると、要素がセットのメンバーであるかどうかを確認できます。

以下は、これらの関数の構文です-

member item list &key :test :test-not :key
member-if predicate list &key :key
member-if-not predicate list &key :key

これらの関数は、テストを満たす特定のアイテムの特定のリストを検索します。 そのような項目が見つからない場合、関数は* nil。*を返します。それ以外の場合、最初の要素として要素を持つリストの末尾が返されます。

検索はトップレベルでのみ行われます。

これらの関数は、述部として使用できます。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(write (member 'zara '(ayan abdul zara riyan nuha)))
(terpri)
(write (member-if #'evenp '(3 7 2 5/3 'a)))
(terpri)
(write (member-if-not #'numberp '(3 7 2 5/3 'a 'b 'c)))

あなたがコードを実行すると、それは次の結果を返します-

(ZARA RIYAN NUHA)
(2 5/3 'A)
('A 'B 'C)

ユニオンを設定

ユニオン関数グループを使用すると、テストに基づいてこれらの関数の引数として提供された2つのリストで集合ユニオンを実行できます。

以下は、これらの関数の構文です-

union list1 list2 &key :test :test-not :key
nunion list1 list2 &key :test :test-not :key
*union* 関数は2つのリストを受け取り、いずれかのリストに存在するすべての要素を含む新しいリストを返します。 重複がある場合、メンバーのコピーが1つだけ返されるリストに保持されます。
*nunion* 関数は同じ操作を実行しますが、引数リストを破壊する場合があります。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq set1 (union '(a b c) '(c d e)))
(setq set2 (union '(#(a b) #(5 6 7) #(f h))
   '(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch)
)

(setq set3 (union '(#(a b) #(5 6 7) #(f h))
   '(#(5 6 7) #(a b) #(g h)))
)
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)

あなたがコードを実行すると、それは次の結果を返します-

(A B C D E)
(#(F H) #(5 6 7) #(A B) #(G H))
(#(A B) #(5 6 7) #(F H) #(5 6 7) #(A B) #(G H))

ご注意ください

ユニオン関数は、3つのベクトルのリストに対して*:test-not# 'mismatch 引数がないと期待どおりに機能しません。 これは、リストがコンスセルで構成されており、値が一見同じように見えても、セルの *cdr 部分が一致しないため、LISPインタープリター/コンパイラーとまったく同じではないためです。 という訳だ;リストを使用して大きなセットを実装することはお勧めしません。 ただし、小さなセットには問題ありません。

交差点を設定

関数の共通部分グループを使用すると、テストに基づいてこれらの関数の引数として提供される2つのリストで共通部分を実行できます。

以下は、これらの関数の構文です-

intersection list1 list2 &key :test :test-not :key
nintersection list1 list2 &key :test :test-not :key

これらの関数は2つのリストを取り、両方の引数リストにあるすべての要素を含む新しいリストを返します。 いずれかのリストに重複エントリがある場合、冗長エントリが結果に表示される場合と表示されない場合があります。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq set1 (intersection '(a b c) '(c d e)))
(setq set2 (intersection '(#(a b) #(5 6 7) #(f h))
   '(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch)
)

(setq set3 (intersection '(#(a b) #(5 6 7) #(f h))
   '(#(5 6 7) #(a b) #(g h)))
)
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)

あなたがコードを実行すると、それは次の結果を返します-

(C)
(#(A B) #(5 6 7))
NIL

交差機能は、交差の破壊的なバージョンです。つまり、元のリストを破壊する可能性があります。

差を設定

関数のset-differenceグループを使用すると、テストに基づいてこれらの関数への引数として提供される2つのリストに対してset-differenceを実行できます。

以下は、これらの関数の構文です-

set-difference list1 list2 &key :test :test-not :key
nset-difference list1 list2 &key :test :test-not :key

set-difference関数は、2番目のリストに表示されない最初のリストの要素のリストを返します。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq set1 (set-difference '(a b c) '(c d e)))
(setq set2 (set-difference '(#(a b) #(5 6 7) #(f h))
   '(#(5 6 7) #(a b) #(g h)) :test-not #'mismatch)
)
(setq set3 (set-difference '(#(a b) #(5 6 7) #(f h))
   '(#(5 6 7) #(a b) #(g h)))
)
(write set1)
(terpri)
(write set2)
(terpri)
(write set3)

あなたがコードを実行すると、それは次の結果を返します-

(A B)
(#(F H))
(#(A B) #(5 6 7) #(F H))

LISP-ツリー

リストのリストとして、コンスセルからツリーデータ構造を構築できます。

ツリー構造を実装するには、コンスセルを特定の順序(たとえば、バイナリツリーの事前順序、順序、および順序)を横断する機能を設計する必要があります。

リストのリストとしてのツリー

私たちはリストの次のリストを形成するコンスセルで構成されたツリー構造を考えてみましょう-

((1 2)(3 4)(5 6))。

概略的に、それは次のように表現できます-

ツリー構造

LISPのツリー関数

ほとんどの場合、特定のニーズに応じて独自のツリー機能を記述する必要がありますが、LISPには、使用できるツリー関数がいくつか用意されています。

すべてのリスト関数とは別に、次の関数は特にツリー構造で動作します-

Sr.No. Function & Description
1
  • copy-tree *x & optional vecp

コンスセルxのツリーのコピーを返します。 車とcdrの両方の方向を再帰的にコピーします。 xがコンスセルでない場合、関数は単にxを変更せずに返します。 オプションのvecp引数がtrueの場合、この関数はコンスセルと同様にベクトルを(再帰的に)コピーします。

2
  • tree-equal *x y & key :test :test-not :key

コンスセルの2つのツリーを比較します。 xとyが両方ともコンスセルの場合、車とCDRが再帰的に比較されます。 xもyもコンスセルでない場合、それらはeqlによって、または指定されたテストに従って比較されます。 :key関数が指定されている場合、両方のツリーの要素に適用されます。

3
  • subst *new old tree & key :test :test-not :key

指定された古いアイテムのオカレンスを、コンスセルのツリーである_tree_の_new_アイテムに置き換えます。

4
  • nsubst *new old tree & key :test :test-not :key

substと同じように機能しますが、元のツリーを破壊します。

5
  • sublis *alist tree & key :test :test-not :key

substのように機能しますが、古いリストと新しいペアの関連付けリスト_alist_を使用します。 ツリーの各要素(もしあれば、:key関数を適用した後)は、alistのcarと比較されます。一致する場合、対応するcdrに置き換えられます。

6
  • nsublis* alist tree & key :test :test-not :key

sublisと同じように機能しますが、破壊的なバージョンです。

例1

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq lst (list '(1 2) '(3 4) '(5 6)))
(setq mylst (copy-list lst))
(setq tr (copy-tree lst))

(write lst)
(terpri)
(write mylst)
(terpri)
(write tr)

あなたがコードを実行すると、それは次の結果を返します-

((1 2) (3 4) (5 6))
((1 2) (3 4) (5 6))
((1 2) (3 4) (5 6))

例2

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq tr '((1 2 (3 4 5) ((7 8) (7 8 9)))))
(write tr)
(setq trs (subst 7 1 tr))
(terpri)
(write trs)

あなたがコードを実行すると、それは次の結果を返します-

((1 2 (3 4 5) ((7 8) (7 8 9))))
((7 2 (3 4 5) ((7 8) (7 8 9))))

独自のツリーを構築する

LISPで使用可能なリスト関数を使用して、独自のツリーを構築してみましょう。

まず、データを含む新しいノードを作成しましょう

(defun make-tree (item)
   "it creates a new node with item."
   (cons (cons item nil) nil)
)

次に、ツリーに子ノードを追加します。2つのツリーノードを取り、2番目のツリーを最初のツリーの子として追加します。

(defun add-child (tree child)
   (setf (car tree) (append (car tree) child))
   tree)

この関数は、指定されたツリーの最初の子を返します。ツリーノードを取得し、そのノードの最初の子を返します。このノードに子ノードがない場合は、nilを返します。

(defun first-child (tree)
   (if (null tree)
      nil
      (cdr (car tree))
   )
)

この関数は、指定されたノードの次の兄弟を返します。引数としてツリーノードを取り、次の兄弟ノードへの参照を返します。ノードにノードがない場合はnilを返します。

(defun next-sibling (tree)
   (cdr tree)
)

最後に、ノード内の情報を返す関数が必要です-

(defun data (tree)
   (car (car tree))
)

この例では、上記の機能を使用しています-

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defun make-tree (item)
   "it creates a new node with item."
   (cons (cons item nil) nil)
)
(defun first-child (tree)
   (if (null tree)
      nil
      (cdr (car tree))
   )
)

(defun next-sibling (tree)
   (cdr tree)
)
(defun data (tree)
   (car (car tree))
)
(defun add-child (tree child)
   (setf (car tree) (append (car tree) child))
   tree
)

(setq tr '((1 2 (3 4 5) ((7 8) (7 8 9)))))
(setq mytree (make-tree 10))

(write (data mytree))
(terpri)
(write (first-child tr))
(terpri)
(setq newtree (add-child tr mytree))
(terpri)
(write newtree)

あなたがコードを実行すると、それは次の結果を返します-

10
(2 (3 4 5) ((7 8) (7 8 9)))

((1 2 (3 4 5) ((7 8) (7 8 9)) (10)))

LISP-ハッシュテーブル

ハッシュテーブルのデータ構造は、キーのハッシュコードに基づいて編成された*キーと値*のペアのコレクションを表します。 キーを使用して、コレクション内の要素にアクセスします。

ハッシュテーブルは、キーを使用して要素にアクセスする必要があるときに使用され、有用なキー値を識別できます。 ハッシュテーブルの各アイテムにはキー/値のペアがあります。 キーは、コレクション内のアイテムにアクセスするために使用されます。

LISPでハッシュテーブルを作成する

Common LISPでは、ハッシュテーブルは汎用コレクションです。 任意のオブジェクトをキーまたはインデックスとして使用できます。

ハッシュテーブルに値を格納する場合、キーと値のペアを作成し、そのキーの下に格納します。 後で、同じキーを使用してハッシュテーブルから値を取得できます。 各キーは単一の値にマッピングされますが、新しい値をキーに保存できます。

LISPのハッシュテーブルは、キーの比較方法に基づいて、eq、eql、またはequalの3つのタイプに分類できます。 ハッシュテーブルがLISPオブジェクトでハッシュされる場合、キーはeqまたはeqlと比較されます。 ハッシュテーブルがツリー構造でハッシュする場合、等しいを使用して比較されます。

*make-hash-table* 関数は、ハッシュテーブルの作成に使用されます。 この関数の構文は次のとおりです-
make-hash-table &key :test :size :rehash-size :rehash-threshold

どこ-

  • key 引数はキーを提供します。
  • *:test *引数は、キーの比較方法を決定します-3つの値# 'eq、#' eql、# 'equalのいずれか、または3つのシンボルeq、eql、またはequalのいずれかを持つ必要があります。 指定しない場合は、eqlが想定されます。
  • *:size *引数は、ハッシュテーブルの初期サイズを設定します。 これはゼロより大きい整数でなければなりません。
  • *:rehash-size *引数は、ハッシュテーブルがいっぱいになったときにサイズをどれだけ増やすかを指定します。 これは、追加するエントリの数であるゼロより大きい整数、または古いサイズに対する新しいサイズの比率である1より大きい浮動小数点数にすることができます。 この引数のデフォルト値は実装依存です。
  • *:rehash-threshold *引数は、ハッシュテーブルが成長しなければならない前に、ハッシュテーブルがどれだけいっぱいになるかを指定します。 これは、ゼロより大きく:rehash-sizeより小さい整数(この場合、テーブルが成長するたびにスケーリングされます)か、ゼロと1の間の浮動小数点数です。 この引数のデフォルト値は実装依存です。

引数なしでmake-hash-table関数を呼び出すこともできます。

ハッシュテーブルからのアイテムの取得とハッシュテーブルへのアイテムの追加

*gethash* 関数は、キーを検索してハッシュテーブルからアイテムを取得します。 キーが見つからない場合は、nilを返します。

次の構文があります-

gethash key hash-table &optional default

ここで-

  • key:関連するキーです

  • ハッシュテーブル:検索するハッシュテーブルです

  • デフォルト:エントリが見つからない場合に返される値、指定されていない場合はnil

    *gethash* 関数は実際には2つの値を返します。2番目の値は、エントリが見つかった場合はtrue、エントリが見つからなかった場合はfalseの述語値です。

ハッシュテーブルにアイテムを追加するには、 setf 関数と gethash 関数を使用できます。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq empList (make-hash-table))
(setf (gethash '001 empList) '(Charlie Brown))
(setf (gethash '002 empList) '(Freddie Seal))
(write (gethash '001 empList))
(terpri)
(write (gethash '002 empList))

あなたがコードを実行すると、それは次の結果を返します-

(CHARLIE BROWN)
(FREDDIE SEAL)

エントリーの削除

*remhash* 関数は、ハッシュテーブル内の特定のキーのエントリを削除します。 これは、エントリが存在する場合はtrue、存在しない場合はfalseとなる述語です。

この関数の構文は次のとおりです-

remhash key hash-table

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq empList (make-hash-table))
(setf (gethash '001 empList) '(Charlie Brown))
(setf (gethash '002 empList) '(Freddie Seal))
(setf (gethash '003 empList) '(Mark Mongoose))

(write (gethash '001 empList))
(terpri)
(write (gethash '002 empList))
(terpri)
(write (gethash '003 empList))
(remhash '003 empList)
(terpri)
(write (gethash '003 empList))

あなたがコードを実行すると、それは次の結果を返します-

(CHARLIE BROWN)
(FREDDIE SEAL)
(MARK MONGOOSE)
NIL

maphash関数

*maphash* 関数を使用すると、ハッシュテーブルの各キーと値のペアに指定された関数を適用できます。

関数とハッシュテーブルの2つの引数を取り、ハッシュテーブル内のキー/値のペアごとに1回関数を呼び出します。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(setq empList (make-hash-table))
(setf (gethash '001 empList) '(Charlie Brown))
(setf (gethash '002 empList) '(Freddie Seal))
(setf (gethash '003 empList) '(Mark Mongoose))

(maphash #'(lambda (k v) (format t "~a => ~a~%" k v)) empList)

あなたがコードを実行すると、それは次の結果を返します-

3 => (MARK MONGOOSE)
2 => (FREDDIE SEAL)
1 => (CHARLIE BROWN)

LISP-入力および出力

Common LISPは、多数の入出力機能を提供します。 すでにformat関数とprint関数を出力に使用しています。 このセクションでは、LISPで提供される最も一般的に使用される入出力関数のいくつかを見ていきます。

入力機能

次の表は、LISPの最も一般的に使用される入力関数を示しています-

Sr.No. Function & Description
1
  • read *& optional input-stream eof-error-p eof-value recursive-p

入力ストリームからLispオブジェクトの印刷された表現を読み込み、対応するLispオブジェクトを構築し、オブジェクトを返します。

2
  • read-preserving-whitespace *& optional in-stream eof-error-p eof-value recursive-p

これは、拡張トークンを終了した文字を正確に判別することが望ましい特殊な状況で使用されます。

3
  • read-line *& optional input-stream eof-error-p eof-value recursive-p

改行で終わるテキスト行を読み取ります。

4
  • read-char *& optional input-stream eof-error-p eof-value recursive-p

入力ストリームから1文字を取得し、文字オブジェクトとして返します。

5
  • unread-char *character & optional input-stream

入力ストリームから最後に読み込まれた文字を入力ストリームの前面に配置します。

6
  • peek-char *& optional peek-type input-stream eof-error-p eof-value recursive-p

入力ストリームから実際に削除せずに、入力ストリームから読み取られる次の文字を返します。

7
  • listen* & optional input-stream

input-streamからすぐに使用できる文字がある場合、述語 listen はtrueで、ない場合はfalseです。

8

read-char-no-hang & optional input-stream eof-error-p eof-value recursive-p

これは read-char と似ていますが、文字を取得しない場合、文字を待たずにすぐにnilを返します。

9
  • clear-input *& optional input-stream

_input-stream._に関連付けられたバッファリングされた入力をクリアします

10
  • read-from-string *string & optional eof-error-p eof-value & key :start :end :preserve-whitespace

文字列の文字を連続して取得し、LISPオブジェクトを構築してオブジェクトを返します。 また、場合によっては、読み取られていない文字列の最初の文字のインデックス、または文字列の長さ(または長さ+1)も返します。

11
  • parse-integer *string & key :start :end :radix :junk-allowed

:startと:endで区切られた文字列の部分文字列を調べます(デフォルトは文字列の先頭と末尾です)。 空白文字をスキップし、整数の解析を試みます。

12
  • read-byte* binary-input-stream & optional eof-error-p eof-value

binary-input-streamから1バイトを読み取り、整数の形式で返します。

キーボードからの入力の読み取り

*read* 関数は、キーボードから入力を取得するために使用されます。 引数をとらない場合があります。

たとえば、コードスニペットを考慮してください-

(write ( + 15.0 (read)))

ユーザーがSTDIN入力から10.2を入力すると、それが返され、

25.2

read関数は、入力ストリームから文字を読み取り、Lispオブジェクトの表現として解析することで文字を解釈します。

main.lispという名前の新しいソースコードファイルを作成し、その中に次のコードを入力します-

; the function AreaOfCircle
; calculates area of a circle
; when the radius is input from keyboard

(defun AreaOfCircle()
(terpri)
(princ "Enter Radius: ")
(setq radius (read))
(setq area (* 3.1416 radius radius))
(princ "Area: ")
(write area))
(AreaOfCircle)

あなたがコードを実行すると、それは次の結果を返します-

Enter Radius: 5 (STDIN Input)
Area: 78.53999

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(with-input-from-string (stream "Welcome to Tutorials Point!")
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (read-char stream))
   (print (peek-char nil stream nil 'the-end))
   (values)
)

あなたがコードを実行すると、それは次の結果を返します-

#\W
#\e
#\l
#\c
#\o
#\m
#\e
#\Space
#\t
#\o
#\Space

出力関数

LISPのすべての出力関数は、出力が送信される_output-streamと呼ばれるオプションの引数を取ります。 言及されていない場合、または_nil、_ output-streamはデフォルトで変数 standard-output の値になります。

次の表は、LISPの最も一般的に使用される出力関数を示しています-

Sr.No. Function and Description
1

write object & key :stream :escape :radix :base :circle :pretty :level :length :case :gensym :array

  • write* _object_&key:stream:escape:radix:base:circle:pretty:level:length:case:gensym:array:readably:right-margin:miser-width:lines:pprint-dispatch

どちらも:streamで指定された出力ストリームにオブジェクトを書き込みます。デフォルトは standard-output の値です。 他の値は、印刷用に設定された対応するグローバル変数にデフォルト設定されます。

2

prin1 object & optional output-stream

  • print* _object_&オプションの_output-stream_ *pprint* _object_&オプションの_output-stream_ *princ* _object_&オプションの_output-stream_

これらの関数はすべて、オブジェクトの出力表現を_output-stream_に出力します。 ただし、次の違いがあります-

  • prin1は、オブジェクトを値として返します。
  • printは、前に改行があり、その後にスペースが続くオブジェクトを印刷します。 オブジェクトを返します。
  • pprintは、末尾のスペースが省略されることを除き、printと同じです。 *princは、出力にエスケープ文字がないことを除いて、prin1と同じです。
3
  • write-to-string* object & key :escape :radix :base :circle :pretty :level :length :case :gensym :array

文字列への書き込み object&キー:エスケープ:基数:ベース:サークル:きれい:レベル:長さ:ケース:gensym:配列:読み取り可能:右マージン:その他の幅:ライン:pprint-dispatch

  • prin1-to-string* _object_ *princ-to-string* _object_

オブジェクトは効果的に印刷され、出力文字は文字列に変換されて返されます。

4
  • write-char *character & optional output-stream

文字を_output-stream、_に出力し、文字を返します。

5
  • write-string *string & optional output-stream & key :start :end

_string_の指定された部分文字列の文字を_output-stream._に書き込みます。

6
  • write-line *string & optional output-stream & key :start :end

write-stringと同じように機能しますが、その後に改行を出力します。

7
  • terpri *& optional output-stream

_output-stream._に改行を出力します

8
  • fresh-line *& optional output-stream

ストリームが行の先頭にない場合にのみ、改行を出力します。

9
  • finish-output* & optional output-stream

    *force-output* &オプションの_output-stream_
    *clear-output* &オプションの_output-stream_
  • 関数 finish-output は、output-streamに送信されたすべての出力が宛先に到達したことを確認しようとし、その後にのみnilを返します。

  • 関数 force-output は、内部バッファーの空化を開始しますが、完了または確認を待たずにnilを返します。

  • 関数 clear-output は、出力を可能な限り少なくして宛先に継続できるように、進行中の未処理の出力操作を中止しようとします。

10

write-byte integer binary-output-stream

_integer._の値である1バイトを書き込みます

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

; this program inputs a numbers and doubles it
(defun DoubleNumber()
   (terpri)
   (princ "Enter Number : ")
   (setq n1 (read))
   (setq doubled (* 2.0 n1))
   (princ "The Number: ")
   (write n1)
   (terpri)
   (princ "The Number Doubled: ")
   (write doubled)
)
(DoubleNumber)

あなたがコードを実行すると、それは次の結果を返します-

Enter Number : 3456.78 (STDIN Input)
The Number: 3456.78
The Number Doubled: 6913.56

フォーマットされた出力

関数 format は、適切にフォーマットされたテキストを生成するために使用されます。 次の構文があります-

format destination control-string &rest arguments

どこで、

  • 宛先は標準出力です
  • control-stringは、出力される文字と印刷ディレクティブを保持します。
  • formatディレクティブ*は、チルダ(〜)、コンマで区切られたオプションのプレフィックスパラメーター、オプションのコロン(:)およびアットマーク(@)修飾子、およびこれがどのようなディレクティブであるかを示す単一の文字で構成されます。

プレフィックスパラメータは通常、整数であり、オプションで符号付き10進数として表記されます。

次の表は、一般的に使用されるディレクティブの簡単な説明を提供します-

Sr.No. Directive & Description
1

~A

ASCII引数が後に続きます。

2

~S

S式が続きます。

3

~D

10進引数の場合。

4

~B

バイナリ引数用。

5

~O

8進引数の場合。

6

~X

16進引数の場合。

7

~C

文字引数用。

8

~F

固定形式の浮動小数点引数の場合。

9

~E

指数浮動小数点引数。

10

~$

ドルと浮動小数点の引数。

11

~%

新しい行が印刷されます。

12

~*

次の引数は無視されます。

13

~?

間接。 次の引数は文字列で、その後の引数はリストでなければなりません。

円の面積を計算するプログラムを書き直しましょう-

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defun AreaOfCircle()
   (terpri)
   (princ "Enter Radius: ")
   (setq radius (read))
   (setq area (* 3.1416 radius radius))
   (format t "Radius: = ~F~% Area = ~F" radius area)
)
(AreaOfCircle)

あなたがコードを実行すると、それは次の結果を返します-

Enter Radius: 10.234 (STDIN Input)
Radius: = 10.234
Area = 329.03473

LISP-ファイルI/O

一般的なLISPによる標準の入力と出力の処理方法について説明しました。 これらの関数はすべて、テキストファイルとバイナリファイルの読み取りと書き込みにも機能します。 唯一の違いは、この場合、使用するストリームは標準の入力または出力ではなく、ファイルへの書き込みまたはファイルからの読み取りという特定の目的のために作成されたストリームです。

この章では、LISPがデータストレージ用のテキストファイルまたはバイナリファイルを作成、開く、閉じる方法について説明します。

ファイルは一連のバイトを表し、テキストファイルまたはバイナリファイルのどちらでもかまいません。 この章では、ファイル管理のための重要な機能/マクロについて説明します。

ファイルを開く

*open* 関数を使用して、新しいファイルを作成するか、既存のファイルを開くことができます。 これは、ファイルを開くための最も基本的な機能です。 ただし、このセクションの後半で説明するように、 *with-open-file* は通常、より便利で一般的に使用されます。

ファイルが開かれると、LISP環境でそれを表すストリームオブジェクトが作成されます。 ストリームに対するすべての操作は、基本的にファイルに対する操作と同等です。

*open* 関数の構文は-
open filename &key :direction :element-type :if-exists :if-does-not-exist :external-format

どこで、

  • _filename_引数は、開くまたは作成するファイルの名前です。
  • _keyword_引数は、ストリームのタイプとエラー処理方法を指定します。
  • *:direction *キーワードは、ストリームが入力、出力、またはその両方を処理するかどうかを指定し、次の値を取ります-
  • :input-入力ストリーム用(デフォルト値)
  • :output-出力ストリーム用
  • :io-双方向ストリーム用
  • :probe-ファイルの存在を確認するだけ。ストリームを開いてから閉じます。
  • *:element-type *は、ストリームのトランザクション単位のタイプを指定します。
  • *:if-exists *引数は、:directionが:outputまたは:ioで、指定された名前のファイルが既に存在する場合に実行されるアクションを指定します。 方向が:inputまたは:probeの場合、この引数は無視されます。 それは次の値を取ります-
  • :error-エラーを通知します。
  • :new-version-同じ名前でより大きなバージョン番号を持つ新しいファイルを作成します。
  • :rename-既存のファイルの名前を変更します。
  • :rename-and-delete-既存のファイルの名前を変更してから削除します。
  • :append-既存のファイルに追加します。
  • :supersede-既存のファイルを置き換えます。
  • nil-ファイルを作成せず、ストリームでもnilを返すだけで失敗を示します。
  • *:if-does-not-exist *引数は、指定された名前のファイルがまだ存在しない場合に実行されるアクションを指定します。 それは次の値を取ります-
  • :error-エラーを通知します。
  • :create-指定された名前で空のファイルを作成し、それを使用します。
  • nil-ファイルもストリームも作成しませんが、代わりに単に失敗を示すためにnilを返します。
  • *:external-format *引数は、ファイル内の文字を表すための実装認識スキームを指定します。

たとえば、次のように/tmpフォルダに保存されているmyfile.txtという名前のファイルを開くことができます-

(open "/tmp/myfile.txt")

ファイルへの書き込みとファイルからの読み取り

*with-open-file* は、読み取り/書き込みトランザクションに関連付けられたストリーム変数を使用して、ファイルの読み取りまたは書き込みを許可します。 ジョブが完了すると、自動的にファイルが閉じられます。 使用すると非常に便利です。

次の構文があります-

with-open-file (stream filename {options}*)
   {declaration}* {form}*
  • _filename_は、開くファイルの名前です。文字列、パス名、またはストリームの場合があります。 *_options_は、関数openのキーワード引数と同じです。

例1

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(with-open-file (stream "/tmp/myfile.txt" :direction :output)
   (format stream "Welcome to Tutorials Point!")
   (terpri stream)
   (format stream "This is a tutorials database")
   (terpri stream)
   (format stream "Submit your Tutorials, White Papers and Articles into our Tutorials   Directory.")
)

terpriやformatなど、前の章で説明したすべての入出力関数は、ここで作成したファイルに書き込むために機能していることに注意してください。

コードを実行すると、何も返されません。ただし、データはファイルに書き込まれます。* :direction:output *キーワードはこれを可能にします。

ただし、 read-line 関数を使用してこのファイルから読み取ることができます。

例2

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(let ((in (open "/tmp/myfile.txt" :if-does-not-exist nil)))
   (when in
      (loop for line = (read-line in nil)

      while line do (format t "~a~%" line))
      (close in)
   )
)

あなたがコードを実行すると、それは次の結果を返します-

Welcome to Tutorials Point!
This is a tutorials database
Submit your Tutorials, White Papers and Articles into our Tutorials Directory.

ファイルを閉じる

*close* 関数はストリームを閉じます。

LISP-構造

構造はユーザー定義のデータ型の1つであり、異なる種類のデータ項目を組み合わせることができます。

構造は、レコードを表すために使用されます。 図書館で本を追跡したいとします。 あなたは、各本に関する次の属性を追跡することができます-

  • タイトル
  • 著者
  • 件名
  • ブックID

構造の定義

LISPの defstruct マクロを使用すると、抽象レコード構造を定義できます。 defstruct ステートメントは、プログラムに複数のメンバーを持つ新しいデータ型を定義します。

*defstruct* マクロの形式について説明するために、Book構造の定義を記述しましょう。 本の構造を次のように定義できます-
(defstruct book
   title
   author
   subject
   book-id
)

ご注意ください

  • 上記の宣言は、4つの*名前付きコンポーネント*を含むブック構造を作成します。したがって、作成されるすべてのブックはこの構造のオブジェクトになります。
  • book-title、book-author、book-subject、book-book-idという名前の4つの関数を定義します。これらは1つの引数、ブック構造を取り、フィールドのタイトル、著者、サブジェクト、ブックのbook-idを返します。オブジェクト。 これらの関数は*アクセス関数*と呼ばれます。
  • シンボルブックはデータ型になり、 typep 述語を使用して確認できます。
  • また、* book-pという名前の暗黙的な関数もあります。これは述語であり、引数が本の場合はtrue、それ以外の場合はfalseです。
  • make-book という名前の別の暗黙関数が作成されます。これは、呼び出されると、アクセス関数での使用に適した4つのコンポーネントを持つデータ構造を作成する constructor です。
  • *#S構文*は構造を指し、それを使用して本のインスタンスを読んだり印刷したりできます。
  • 1つの引数のcopy-bookという名前の暗黙的な関数も定義されています。 ブックオブジェクトを取得し、最初のオブジェクトのコピーである別のブックオブジェクトを作成します。 この機能は*コピー機能*と呼ばれます。
  • setf を使用して、ブックのコンポーネントを変更できます。たとえば、
(setf (book-book-id book3) 100)

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defstruct book
   title
   author
   subject
   book-id
)

( setq book1 (make-book :title "C Programming"
   :author "Nuha Ali"
   :subject "C-Programming Tutorial"
   :book-id "478")
)

( setq book2 (make-book :title "Telecom Billing"
   :author "Zara Ali"
   :subject "C-Programming Tutorial"
   :book-id "501")
)

(write book1)
(terpri)
(write book2)
(setq book3( copy-book book1))
(setf (book-book-id book3) 100)
(terpri)
(write book3)

あなたがコードを実行すると、それは次の結果を返します-

#S(BOOK :TITLE "C Programming" :AUTHOR "Nuha Ali" :SUBJECT "C-Programming Tutorial" :BOOK-ID "478")
#S(BOOK :TITLE "Telecom Billing" :AUTHOR "Zara Ali" :SUBJECT "C-Programming Tutorial" :BOOK-ID "501")
#S(BOOK :TITLE "C Programming" :AUTHOR "Nuha Ali" :SUBJECT "C-Programming Tutorial" :BOOK-ID 100)

LISP-パッケージ

プログラミング言語の一般的な用語では、パッケージは、名前のセットを別のセットから分離する方法を提供するために設計されています。 あるパッケージで宣言されたシンボルは、別のパッケージで宣言された同じシンボルと競合しません。 このようにして、パッケージは独立したコードモジュール間の名前の競合を減らします。

LISPリーダーは、検出したすべてのシンボルのテーブルを保持しています。 新しい文字シーケンスを見つけると、新しいシンボルを作成し、シンボルテーブルに保存します。 このテーブルはパッケージと呼ばれます。

現在のパッケージは、特別な変数 package によって参照されます。

LISPには2つの定義済みパッケージがあります-

  • common-lisp -定義されたすべての関数と変数のシンボルが含まれています。
  • common-lisp-user -common-lispパッケージと、編集およびデバッグツールを備えた他のすべてのパッケージを使用します。要するにcl-userと呼ばれます

LISPのパッケージ関数

次の表は、パッケージの作成、使用、操作に使用される最も一般的に使用される機能を示しています-

Sr.No. Function and Description
1
  • make-package *package-name &key :nicknames :use

指定されたパッケージ名で新しいパッケージを作成して返します。

2
  • in-package *package-name &key :nicknames :use

パッケージを最新にします。

3
  • in-package* name

このマクロは、 package をnameという名前のパッケージに設定します。これは、シンボルまたは文字列でなければなりません。

4
  • find-package *name

パッケージを検索します。 その名前またはニックネームを持つパッケージが返されます。そのようなパッケージが存在しない場合、find-packageはnilを返します。

5
  • rename-package *package new-name &optional new-nicknames

パッケージの名前を変更します。

6
  • list-all-packages*

この関数は、現在Lispシステムに存在するすべてのパッケージのリストを返します。

7

delete-package package

パッケージを削除します。

LISPパッケージの作成

*defpackage* 関数は、ユーザー定義パッケージを作成するために使用されます。 次の構文があります-
(defpackage :package-name
   (:use :common-lisp ...)
   (:export :symbol1 :symbol2 ...)
)

どこで、

  • package-nameはパッケージの名前です。

  • :useキーワードは、このパッケージに必要なパッケージ、つまり、このパッケージのコードで使用される機能を定義するパッケージを指定します。

  • :exportキーワードは、このパッケージの外部にあるシンボルを指定します。

    *make-package* 関数は、パッケージの作成にも使用されます。 この関数の構文は次のとおりです-
make-package package-name &key :nicknames :use

引数とキーワードの意味は以前と同じです。

パッケージを使用する

パッケージを作成したら、それを現在のパッケージにすることで、このパッケージのコードを使用できます。 in-package マクロは、環境内でパッケージを最新にします。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(make-package :tom)
(make-package :dick)
(make-package :harry)
(in-package tom)
(defun hello ()
   (write-line "Hello! This is Tom's Tutorials Point")
)

(hello)
(in-package dick)
(defun hello ()
   (write-line "Hello! This is Dick's Tutorials Point")
)

(hello)
(in-package harry)
(defun hello ()
   (write-line "Hello! This is Harry's Tutorials Point")
)

(hello)
(in-package tom)
(hello)
(in-package dick)
(hello)
(in-package harry)
(hello)

あなたがコードを実行すると、それは次の結果を返します-

Hello! This is Tom's Tutorials Point
Hello! This is Dick's Tutorials Point
Hello! This is Harry's Tutorials Point

パッケージを削除する

*delete-package* マクロを使用すると、パッケージを削除できます。 次の例はこれを示しています-

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(make-package :tom)
(make-package :dick)
(make-package :harry)
(in-package tom)
(defun hello ()
   (write-line "Hello! This is Tom's Tutorials Point")
)

(in-package dick)
(defun hello ()
   (write-line "Hello! This is Dick's Tutorials Point")
)

(in-package harry)
(defun hello ()
   (write-line "Hello! This is Harry's Tutorials Point")
)

(in-package tom)
(hello)
(in-package dick)
(hello)
(in-package harry)
(hello)
(delete-package tom)
(in-package tom)
(hello)

あなたがコードを実行すると、それは次の結果を返します-

Hello! This is Tom's Tutorials Point
Hello! This is Dick's Tutorials Point
Hello! This is Harry's Tutorials Point
*** - EVAL: variable TOM has no value

LISP-エラー処理

一般的なLISPの用語では、例外は条件と呼ばれます。

実際、条件は従来のプログラミング言語の例外よりも一般的です。*条件*は、さまざまなレベルの関数呼び出しスタックに影響を与える可能性のある発生、エラー、またはエラーを表すためです。

LISPの条件処理メカニズムは、コールスタックの上位レベルのコードが作業を継続できる一方で、条件を使用して警告を通知する(たとえば、警告を出力する)ようにそのような状況を処理します。

LISPの条件処理システムには3つの部分があります-

  • 状態の通知
  • 状態の処理
  • プロセスを再起動します

条件の処理

ここで概念を説明するために、ゼロ除算条件から生じる条件を処理する例を取り上げましょう。

条件を処理するには、次の手順を実行する必要があります-

  • 条件の定義-「条件とは、クラスが条件の一般的な性質を示し、インスタンスデータが条件の通知につながる特定の状況の詳細に関する情報を保持するオブジェクトです」。 +定義条件マクロは、次の構文を持つ条件を定義するために使用されます-
(define-condition condition-name (error)
   ((text :initarg :text :reader text))
)
  • 新しい条件オブジェクトは、MAKE-CONDITIONマクロを使用して作成されます。このマクロは、*:initargs *引数に基づいて新しい条件のスロットを初期化します。

私たちの例では、次のコードは条件を定義します-

(define-condition on-division-by-zero (error)
   ((message :initarg :message :reader message))
)
  • ハンドラーの記述-条件ハンドラーは、その上で通知された条件を処理するために使用されるコードです。 通常、エラー関数を呼び出す上位レベル関数の1つで記述されます。 条件が通知されると、通知メカニズムは条件のクラスに基づいて適切なハンドラーを検索します。 +各ハンドラーは-
  • タイプ指定子。処理できる条件のタイプを示します
  • 単一の引数、条件をとる関数 +条件が通知されると、通知メカニズムは、条件タイプと互換性のある最も新しく確立されたハンドラーを見つけ、その関数を呼び出します。 +マクロ handler-case は条件ハンドラーを確立します。 ハンドラーケースの基本形-
(handler-case expression error-clause*)

ここで、各エラー句は次の形式です-

condition-type ([var]) code)
  • フェーズの再開 * +これは実際にプログラムをエラーから回復するコードであり、条件ハンドラーは適​​切な再起動を呼び出すことで条件を処理できます。 通常、再起動コードは中間レベルまたは低レベルの関数に配置され、条件ハンドラーはアプリケーションの上位レベルに配置されます。 + handler-bind マクロを使用すると、再起動関数を提供でき、関数呼び出しスタックを巻き戻さずに下位レベルの関数で続行できます。 言い換えると、制御の流れは依然として下位レベルの機能にあります。 + *handler-bind の基本形式は次のとおりです-
(handler-bind (binding*) form*)

各バインディングは次のリストです-

  • 条件タイプ

  • 1つの引数のハンドラー関数

    *invoke-restart* マクロは、指定された名前を引数として使用して、最後にバインドされた再起動関数を見つけて呼び出します。

複数回再起動することができます。

この例では、除数引数がゼロの場合にエラー条件を作成するdivision-functionという名前の関数を記述することにより、上記の概念を示します。 値1を返すこと、除数2を送信して再計算すること、または1を返すことの3つの方法を提供する3つの匿名関数があります。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(define-condition on-division-by-zero (error)
   ((message :initarg :message :reader message))
)

(defun handle-infinity ()
   (restart-case
      (let ((result 0))
         (setf result (division-function 10 0))
         (format t "Value: ~a~%" result)
      )
      (just-continue () nil)
   )
)

(defun division-function (value1 value2)
   (restart-case
      (if (/= value2 0)
         (/value1 value2)
         (error 'on-division-by-zero :message "denominator is zero")
      )

      (return-zero () 0)
      (return-value (r) r)
      (recalc-using (d) (division-function value1 d))
   )
)

(defun high-level-code ()
   (handler-bind
      (
         (on-division-by-zero
            #'(lambda (c)
               (format t "error signaled: ~a~%" (message c))
               (invoke-restart 'return-zero)
            )
         )
         (handle-infinity)
      )
   )
)

(handler-bind
   (
      (on-division-by-zero
         #'(lambda (c)
            (format t "error signaled: ~a~%" (message c))
            (invoke-restart 'return-value 1)
         )
      )
   )
   (handle-infinity)
)

(handler-bind
   (
      (on-division-by-zero
         #'(lambda (c)
            (format t "error signaled: ~a~%" (message c))
            (invoke-restart 'recalc-using 2)
         )
      )
   )
   (handle-infinity)
)

(handler-bind
   (
      (on-division-by-zero
         #'(lambda (c)
            (format t "error signaled: ~a~%" (message c))
            (invoke-restart 'just-continue)
         )
      )
   )
   (handle-infinity)
)

(format t "Done."))

あなたがコードを実行すると、それは次の結果を返します-

error signaled: denominator is zero
Value: 1
error signaled: denominator is zero
Value: 5
error signaled: denominator is zero
Done.

前述の「条件システム」とは別に、Common LISPはエラーを通知するために呼び出されるさまざまな機能も提供します。 ただし、エラーが通知された場合の処理​​は、実装に依存します。

LISPのエラーシグナル関数

次の表は、警告、ブレーク、致命的ではない致命的エラーを通知する一般的に使用される機能を示しています。

ユーザープログラムはエラーメッセージ(文字列)を指定します。 関数はこのメッセージを処理し、ユーザーに表示する場合としない場合があります。

エラーメッセージは、 format 関数を適用して作成する必要があり、先頭または末尾に改行文字を含めることはできません。また、エラーを示す必要はありません。LISPシステムは、優先スタイルに従ってこれらを処理します。

Sr.No. Function and Description
1
  • error *format-string &rest args

致命的なエラーを通知します。 この種のエラーから続行することは不可能です。したがって、エラーは呼び出し元に戻ることはありません。

2
  • cerror *continue-format-string error-format-string &rest args

エラーを通知し、デバッガーに入ります。 ただし、エラーを解決した後、デバッガーからプログラムを続行できます。

3
  • warn *format-string &rest args

エラーメッセージを出力しますが、通常はデバッガーには入りません

4
  • break* &optional format-string &rest args

プログラムされたエラー処理機能によるインターセプトの可能性を許可せずに、メッセージを出力し、デバッガーに直接入ります。

この例では、階乗関数は数値の階乗を計算します。ただし、引数が負の場合、エラー条件が発生します。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defun factorial (x)
   (cond ((or (not (typep x 'integer)) (minusp x))
      (error "~S is a negative number." x))
      ((zerop x) 1)
      (t (* x (factorial (- x 1))))
   )
)

(write(factorial 5))
(terpri)
(write(factorial -1))

あなたがコードを実行すると、それは次の結果を返します-

120
*** - -1 is a negative number.

LISP-CLOS

Common LISPは、オブジェクト指向プログラミングの進歩よりも数十年前に先んじました。 ただし、オブジェクト指向は後の段階で組み込まれました。

クラスの定義

*defclass* マクロを使用すると、ユーザー定義のクラスを作成できます。 クラスをデータ型として確立します。 次の構文があります-
(defclass class-name (superclass-name*)
   (slot-description*)
   class-option*))

スロットは、データまたはフィールドを格納する変数です。

スロット記述の形式は(slot-name slot-option *)です。各オプションは、名前、式、その他のオプションが続くキーワードです。 最も一般的に使用されるスロットオプションは-

  • *:accessor *関数名
  • *:initform *式
  • *:initarg *シンボル

たとえば、3つのスロットの長さ、幅、高さを持つBoxクラスを定義してみましょう。

(defclass Box ()
   (length
   breadth
   height)
)

スロットへのアクセスおよび読み取り/書き込み制御の提供

スロットにアクセス、読み取り、または書き込みできる値がない限り、クラスはほとんど役に立ちません。

クラスを定義するときに、各スロットに accessors を指定できます。 たとえば、私たちのBoxクラスを取ります-

(defclass Box ()
   ((length :accessor length)
      (breadth :accessor breadth)
      (height :accessor height)
   )
)

スロットの読み取りと書き込みに別々の accessor 名を指定することもできます。

(defclass Box ()
   ((length :reader get-length :writer set-length)
      (breadth :reader get-breadth :writer set-breadth)
      (height :reader get-height :writer set-height)
   )
)

クラスのインスタンスの作成

汎用関数 make-instance は、クラスの新しいインスタンスを作成して返します。

次の構文があります-

(make-instance class {initarg value}*)

長さ、幅、高さの3つのスロットを持つBoxクラスを作成しましょう。 これらのフィールドに値を設定するには、3つのスロットアクセサーを使用します。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defclass box ()
   ((length :accessor box-length)
      (breadth :accessor box-breadth)
      (height :accessor box-height)
   )
)
(setf item (make-instance 'box))
(setf (box-length item) 10)
(setf (box-breadth item) 10)
(setf (box-height item) 5)
(format t "Length of the Box is ~d~%" (box-length item))
(format t "Breadth of the Box is ~d~%" (box-breadth item))
(format t "Height of the Box is ~d~%" (box-height item))

あなたがコードを実行すると、それは次の結果を返します-

Length of the Box is 10
Breadth of the Box is 10
Height of the Box is 5

クラスメソッドの定義

*defmethod* マクロを使用すると、クラス内でメソッドを定義できます。 次の例では、Boxクラスを拡張して、volumeという名前のメソッドを含めます。

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defclass box ()
   ((length :accessor box-length)
      (breadth :accessor box-breadth)
      (height :accessor box-height)
      (volume :reader volume)
   )
)

; method calculating volume

(defmethod volume ((object box))
   (* (box-length object) (box-breadth object)(box-height object))
)

 ;setting the values

(setf item (make-instance 'box))
(setf (box-length item) 10)
(setf (box-breadth item) 10)
(setf (box-height item) 5)

; displaying values

(format t "Length of the Box is ~d~%" (box-length item))
(format t "Breadth of the Box is ~d~%" (box-breadth item))
(format t "Height of the Box is ~d~%" (box-height item))
(format t "Volume of the Box is ~d~%" (volume item))

あなたがコードを実行すると、それは次の結果を返します-

Length of the Box is 10
Breadth of the Box is 10
Height of the Box is 5
Volume of the Box is 500

継承

LISPでは、オブジェクトを別のオブジェクトの観点から定義できます。 これは* inheritance。*と呼ばれます。新しいまたは異なる機能を追加することで、派生クラスを作成できます。 派生クラスは、親クラスの機能を継承します。

次の例はこれを説明します-

main.lispという名前の新しいソースコードファイルを作成し、次のコードを入力します。

(defclass box ()
   ((length :accessor box-length)
      (breadth :accessor box-breadth)
      (height :accessor box-height)
      (volume :reader volume)
   )
)

; method calculating volume
(defmethod volume ((object box))
   (* (box-length object) (box-breadth object)(box-height object))
)

;wooden-box class inherits the box class
(defclass wooden-box (box)
((price :accessor box-price)))

;setting the values
(setf item (make-instance 'wooden-box))
(setf (box-length item) 10)
(setf (box-breadth item) 10)
(setf (box-height item) 5)
(setf (box-price item) 1000)

; displaying values
(format t "Length of the Wooden Box is ~d~%" (box-length item))
(format t "Breadth of the Wooden Box is ~d~%" (box-breadth item))
(format t "Height of the Wooden Box is ~d~%" (box-height item))
(format t "Volume of the Wooden Box is ~d~%" (volume item))
(format t "Price of the Wooden Box is ~d~%" (box-price item))

あなたがコードを実行すると、それは次の結果を返します-

Length of the Wooden Box is 10
Breadth of the Wooden Box is 10
Height of the Wooden Box is 5
Volume of the Wooden Box is 500
Price of the Wooden Box is 1000