🎾

Racket: Racketの基本データ型

2024/07/07に公開

はじめに

この記事では、Racketの基本データ型について詳しく説明します。
RacketLISPに由来する関数型プログラミング言語で、教育目的で広く利用されています。

1. Racketとは

RacketSchemeから派生した言語で、初心者が関数型プログラミングを学びやすいように設計されています。
この言語は、教育だけでなく研究目的でも広く利用されています。

2. 動的データ型と不変性 (immutable)

Racketのデータ型には、動的な特性と不変性があります。
動的データ型を使うことで、型宣言なしでデータ操作が可能になり、開発者はより自由にコーディングできます。
一方で、不変性はデータの一貫性を保ち、プログラムのバグを減少させます。

2.1 動的データ型

Racketでは、データ型を動的に扱います。これにより、プログラムは実行時にデータの型を柔軟に変更できます。

2.2 不変性 (immutable)

Racketでは、データは基本的に不変 (immutable)です。
これは、一度作成したデータはその後、変更できないことを意味します。

たとえば、次のコードでのように変数 x の値を再定義しようとすると、エラーが発生します。

sample.rkt
(define x 10)
(println x)     ; 10
(define x 20)   ; change x to 20
(println x)

実行すると、下記のようにidentifier already definedエラーが発生します。

racket実行結果
module: identifier already defined
  at: x

値を上書きしたい場合は、下記のようにset!を使用します:

sample2.rkt
(define x 10)
(println x)   ; 10
(set! x 20)   ; change x to 20
(println x)

3. Racketの基本データ型

Racketでは多様なデータ型が存在しますが、本記事では数値型、文字列型、ブーリアン型などの基本データ型に焦点を当てて解説します。

3.1 数値型

Racketには数をあらわす数値型があり、型はnumberです。
数値型は算術演算を行なうために使用します。
数値型には、整数型、有理数型、実数型があります。

たとえば、整数型を使用して以下のような簡単な算術演算を行なえます:

integer-calc.rkt
(define my-integer 42)
(+ my-integer 8)  ; 50

特殊な数値

特殊な数として、以下のシンボルが定義されています。

  • +inf.0 : 正の無限大
  • -inf.0 : 負の無限大
  • +nan.0 / -nan.0: 非数 (数値ではない)

3.2 整数型

整数型は、正負の整数および0を表現するために使用します。整数型の型はintegerです。

my-integer.rkt
(define my-integer  42)

上記の例では、変数my-integer42 を代入しています。整数型には、以下のような算術演算子を使用できます。

  • + : 加算
  • - : 減算
  • * : 乗算
  • `/ : 除算
  • quotient: 整数除算
  • remainder: 余りの演算
  • modulo : 剰余演算

整数型は、2進数8進数16進数でも記述できます。
下記のように接頭辞 (#b,#o,#x) を付けて記述します。

  • 2進数: #b1011 = 11
  • 8進数: #o15 = 13
  • 16進数: #xa3 = 163

3.3 有理数型

有理数型は、分数を表現するために使用します。有理数型の型はrationalです。

my-rational.rkt
(define my-rational 3/4)

上記の例では、変数my-rational に 3/4 を代入しています。有理数型には、以下のような算術演算子を使用できます。

  • + : 加算
  • - : 減算
  • * : 乗算
  • / : 除算

3.4 実数型

実数型は、小数点以下の桁数を持つ数を表現するために使用されます。実数型の型は、float またはrealです。

my-real.rkt
(define my-real 3.141592)

上記の例では、変数my-real3.141592 を代入しています。実数型には、以下のような算術演算子を使用できます。

  • + : 加算
  • - : 減算
  • * : 乗算
  • / : 除算

3.5 文字列型

文字列型は、文字列を表現するために使用され、型はstringです。
文字列は、"で囲みます。
文字列型では、文字列の生成、連結、部分取得など、さまざまな文字列操作が可能です。

  • string-append : 文字列を連結する
  • string-length : 文字列の長さを取得する
  • string-ref : 文字列の指定した位置の文字を取得する

下記のように、文字列を操作してメッセージを作成できます:

my-string.rkt
(define my-string "hello ")
(displayln (string-append my-string "world"))

3.6 文字型

文字型は、Unicode文字を表現するために使用され、文字型の型はcharです。
文字型では、文字を#\fのように#\<文字>の形で記述します。

my-char.rkt
(define my-char #\あ)

my-char
#\あ

(char->integer my-char)
12354

上記の例では、変数 my-charに文字を代入しています。文字型には、以下のような比較演算子を使用できます。

  • char=? : 文字が等しいかどうかを比較する
  • char<? : 文字の大小関係を比較する
  • char>? : 文字の大小関係を比較する
  • char<=? : 文字の大小関係を比較する
  • char>=? : 文字の大小関係を比較する

3.7 ブーリアン型

ブーリアン型は真偽値をとるデータ型で、型はbooleanです。
ブーリアン型は、真 (#t) か偽 (#f) のいずれかの値となります。
数値の比較などで、条件の審議を表すために使用します。

my-boolean.rkt
(define my-boolean #t)

上記の例では、変数my-boolean#tを代入しています。
ブーリアン型には、ブーリアン型には、以下のような論理演算子が使えます。

  • not : 否定
  • and : 論理積
  • or : 論理和
  • xor : 排他的論理和

3.8 シンボル型

シンボル型は、変数名や関数名などに使われる文字列で、型はsymbolです。
シンボルは、文字列をそのまま記述します。"でくくりません。
その代わり、空白や特殊文字 (例:#) はシンボルとして使用できません。

Racketはシンボルが見付かると、シンボルにバインドされた値を表示します。
シンボルそのものを記述したいときは、'でシンボルをエスケープします。

my-simbol.rkt
(define my-symbol 'hello)

my-symbol
'hello

上記の例では、my-symbolにシンボルhelloを代入しています。
シンボルを表示するため、先頭に'がついています。

3.9 ペア型

ペア型は、LISPにおける基本データであるcons-cellを示すデータ型です。
cons-cellは 2つのデータのペアからなるデータで、最初の要素をcar、次の要素をcdrと呼びます。
Racketでは、2つのデータを.で区切って示します。

my-pair.rkt
(cons 1 2)
'(1 . 2)

上記の例は、car1cdr2を代入したcons-cellを作成します。
図解すると:

'(1 . 2)
    +---+---+
    | 1 | 2 |
    +---+---+

となります。

3.10 リスト型

リスト型は、複数の要素を 1つにまとめたものです。リスト型の型はlistです。
リストは、各要素を空白で区切って表示します。

下記は、要素 1, 2, 3 をもつリストを作成します:

'(1 2 3)
(list 1 2 3)
'(1 2 3)

リスト型の構造

リストは、cons-cellを複数繋いだものです。各cons-cellcar部はリストの要素となるデータ、cdr部は次のcons-cellへのポイントがはいります。
最後のcons-cellでは、cdr部に空のリスト'()がはいります。

たとえば、リスト( 1 2 3)を図解すると:

'(1 2 3)
    +-----+------+     +-----+------+     +-----+-----+
    |  1  |  o---+---->|  2  |  o---+---->|  3  | '() |
    +-----+------+     +-----+------+     +-----+-----+

と、なります。

4. 特殊なデータ型

Racketでは、システムが扱うための特殊なデータ型や定数があります。
このセクションでは、これらを説明します。

4.1 void

void型は、戻り値を必要としない手続きに使用される特殊な型です。
たとえば、副作用のみを目的とする関数で使われます。
この型の使用は、プログラムの出力に影響を与えず、内部状態の変更のみを行います。

下記のコードは、値を返さない手続きvoid-procedureを定義しており、値を返す必要がないのでvoidを使用しています:

void-procedure.rkt
(define void-procedure
    (void))    ;  ←  値を返さない

void-procedureの実行結果は、次のようになります:

> void-procedure
>

void-procedureは値を返さないので、プロンプトが表示されます。

4.2 undefined

undefinedは、未定義の値を表現するために使用される定数です。
Racket で未定義の変数を参照しようとするとundefinedとなり、エラーが発生します。

(define y 1)
(display (+ x y))     ;  xが未定義(undefined)なのでエラー

x: undefined;
 cannot reference an identifier before its definition
  in module: top-level
 [,bt for context]

おわりに

以上で、Racketの基本データ型を説明しました。
つぎは、Racketでの構文や条件分岐、関数の定義などを学習していきましょう。
Racketを使ってプログラミングを学ぶことで、関数型プログラミングの理解が深まるでしょう。

それでは、Happy Hacking!

技術用語と注釈

技術用語とのその注釈です。

  • Racket:
    Scheme言語を基にした関数型プログラミング言語で、言語理論や実験的プロジェクトに適した言語。

  • 動的データ型:
    実行時にデータの型が決定される言語の特性

  • 不変性 (immutable):
    オブジェクトが一度作成されると、その状態を変更できない性質。

  • ペア型:
    2つの値を持つデータ構造。

  • リスト型:
    数の要素を一連の連結リストとして格納するデータ型。

  • cons-cell:
    2つの要素、carcdrからなるデータ構造。

参考資料

Web

GitHubで編集を提案

Discussion