🎾

Education: Racket言語における比較演算子: 数値型と文字列型の実践ガイド

2023/04/16に公開

はじめに

Racket 言語の比較演算子について説明します。
Racket は LISP[1]、Scheme の流れを組んだ関数型言語[2]で、さまざまなデータ型をあらかじめ組み込んでいます。
それぞれのデータ我と似合わせて比較演算子があり、これらを使用するためには経験が必要です。

この記事では、代表的な型である数値型と文字列型について比較演算子を紹介します。これにより、Racket 言語の特徴が少しでもわかると幸いです。

Racket 言語とは

Racket言語の特徴

Racket は、関数型プログラミングおよびオブジェクト指向プログラミングの双方のパラダイムをサポートする汎用プログラミング言語です。 Racket の特徴は、以下のとおりです。

  • 関数型およびオブジェクト指向プログラミングの両方をサポート
  • シンプルで理解しやすいシンタックス
  • マクロをサポートし、機能を拡張することができる
  • 標準ライブラリが豊富であり、さまざまな実用的なツールを提供する

比較演算子

Racket ではデータ型のそれぞれに対して比較演算子があります。代表的なデータ型である数値型と文字列型について、コード例をあげて紹介します。

数値の比較演算子

Racket では、整数、有理数、実数の 3つのデータ型を組み合わせた操作が可能です。ここでは、Racket 言語における数値の比較演算子について説明します。

数値の比較演算子一覧

数値の比較演算子は、表に示すとおりです。

演算子 説明
< より小さい
> より大きい
<= 以下
>= 以上
= 等しい

重要事項

  • Racket には等しくないを示す演算子はありません

数値比較関数の例

2つの数値を比較する関数の例を紹介します。

compare-numbers.rkt
(define (compare-numbers a b)
   (cond
      [(< a b) "aはbより小さい"]
      [(> a b) "aはbより大きい"]
      [(= a b) "aとbは等しい"]))

上記の例では、2つの数値 a と b を比較するcompare-numbersという関数を定義しています。condを使って数値の比較を行い、その結果に応じた文字列を返しています。

関数使用例:

> (compare-numbers 4 5)
"aはbより小さい"

> (compare-numbers 3/2 1)
"aはbより大きい"

> (compare-numbers 3/2 "abc")
<: contract violation
  expected: real?
  given: "abc"

最後の例のように、数値以外のデータを入れると「データ型が違う」というエラーが発生します。
回避するには、数値型かどうかをチェックする関数number?を使って、数値以外のデータをはじく必要があります。

以下の例は、number?を用いて数値型以外にも対応した数値を比較する関数の例です。

compare-values.rkt
(define (compare-values a b)
   (cond
      [(and (number? a) (number? b))
            (cond
               [(< a b) "aはbより小さい"]
               [(> a b) "aはbより大きい"]
               [(= a b) "aとbは等しい"])]
      [else "数値ではありません"]))

重要事項

  • 引数が数値型以外の場合は、"数値ではありません"と表示する

関数使用例:

> (compare-values 1 2)
"aはbより小さい"

> (compare-values 2 2)
"aとbは等しい"が表示されます

> (compare-values "a" "b")
"数値ではありません"

データ型を横断した比較

Racket では、整数と有理数、実数と有理数といった別々のデータ型の数値も比較できます。
例をあげると、

> (> 1 1.5)
#f
> (> 1.5 2/3)
#t
> (> 1.5 5/3)
#f

となります。

複数の数値の比較

複数の数値を比較することもできます。
例をあげると、

> (> 3 2)
#t
> (> 3 2 2)
#f
> (> 3 2 1)
#t

となります。
複数の数値がある場合は、2 項目ごとに数値を比較して、その and を返します。(> 3 2 2 )の場合は、(> 2 2)の結果が#fとなるので、#fが返ります。

文字列の比較演算子

Racket では、文字列は Unicode 標準で表されます。文字列の比較には、Unicode を使用します。
この説では、Racket 言語の文字列の比較演算子について説明します。

文字列の比較演算子の一覧

文字列の比較演算子は、表に示すとおりです

演算子 説明
string=? 等しい
string<? アルファベット順で小さい
string>? アルファベット順で大きい
string<=? アルファベット順で小さいか等しい
string>=? アルファベット順で大きいか等しい
string-ci=? 大小文字を区別しないで、等しい
string-ci<? 大小文字を区別せず、小さい
string-ci>? 大小文字を区別せず、大きい
string-ci<=? 大小文字を区別せず、小さいか等しい
string-ci>=? 大小文字を区別せず、きいか等しい

使用例を以下に示します。

(string<? "apple" "banana") ; #t
(string>? "apple" "banana") ; #f
(string<=? "apple" "banana") ; #t
(string>=? "apple" "banana") ; #f
(string=? "apple" "orange") ; #f
(string-ci=? "apple" "Apple") ; #t
(string-ci<? "apple" "Banana") ; #t
(string-ci>? "apple" "Banana") ; #f
(string-ci<=? "apple" "Banana") ; #t
(string-ci>=? "apple" "Banana") ; #f

string-ci=?のように、最後に'ci'をつけた演算子は大文字と小文字を区別しないで比較します。
英語の大小文字を同じ文字として扱うか否かは、状況に応じて使い分ける必要があります。

日本語などの比較

Racket では文字列の表現に Unicode を用いているため、日本語のような英数字以外の比較も可能です
日本語での文字列比較の例は、

> (string<? "こんにちは" "こんばんは")
#t

となります。

複数の文字列の比較

複数の文字列の比較も可能です。
複数の比較の例は、

> (string>? "abc" "abb" "ab")
#t

> (string>? "abc" "abb" "abb")
#f

となります。

同等性の比較演算子

Racket では 2つのデータが「同等」であるかどうかを比較するために、さまざまな演算子が用意されています。
いかに代表的な演算子とその特徴を紹介します。

演算子 説明
= 2つの数値が等しい (= 2 2)#t
eq? 2つのデータが同じオブジェクトを参照しているときに等しい(#t) (eq? 'a 'a) → `#t'
eqv? 2つのデータ(オブジェクト)の値が等しい(#t) (eqv? "abc" "abc")#t
equal? 複合データ型[3]を再帰的にすべて比較 (equal? '(a b c) '(a b c))#t

重要事項

  • = : 数値型以外の型の場合はエラーとなる
  • eq : 結果は、Racket の実装に依存する
  • equal : リスト型、ベクター型のような複数のデータ型をまとめた複合データ型に用いられる

= 演算子

使用方法: (= a b)

=演算子は、2つの数値が等しいかどうかを比較します。数値以外の型を比較するとエラーが発生します。
以下は=演算子を使った Racket プログラムの例です。

> (= 1 2)
#f
> (= 2 2)
"t
> (= 2 2.0 )  ; 整数と実数の比較
#t
> (= 1 4/4)   ; 整数と有理数の比較
#t
> (= "apple" "apple") ; エラー
=: contract violation
  expected: number?
  given: "apple"

eq? 演算子

使用方法: (eq? a b)

eq?演算子は、2つのデータが同じオブジェクトを参照している場合、真('#t')となります。
以下はeq?演算子を使った Racket プログラムの例です。

> (define a 12)
> (define b 12)
> (define c b)
> (eq? a b)
#t
> (eq? b c)
#t
> (eq? 'a 'a)
#t
> (eq? "apple" "banana")
#f

eqv? 演算子

使用方法: (eqv? a b)

eqv?演算子は、2つのデータ型でデータの値が等しい場合に真(#t)となります。
以下はeqv?演算子を使った Racket プログラムの例です。

> (define a 12)
> (define b 12)
> (eqv? a b)
#t
> (eqv? 'a 'a)
#t
> (eqv? "apple" "banana")
#f
>(eqv? '(a b c) '(a b c))
#f
>(eqv? '(a b c) '(a b d))
#f

重要事項

  • リストは、異なるオブジェクトが精製されるため等しくない(#f)となる

equal? 演算子

使用方法: (equal? a b)

equal?演算子は渡されたデータ型の中身が等しいかどうかを再帰的にすべて比較します。
リスト型、ベクター型のような複数の要素からなるデータ型の場合、複数の要素それぞれに対して等しいかチェックします。
以下はequal?演算子を使った Racket プログラムの例です。

> (define a 12)
> (define b 12)
> (equal? a b)
#t
> (equal? 'a 'a)
#t
> (equal? "apple" "banana")
#f
>(equal? '(a b c) '(a b c))
#t
>(equal? '(a b c) '(a b d))
#f

equal?eqv?と違い、リストの中のオブジェクトも比較するので(equal? '(a b c) '(a b c))は等しい(#t)となります。

特殊な比較演算子

データが特殊な値であるかをチェックする演算子もあります。ここでは、代表的なものとその特徴を特徴します。

演算子 説明
zero? 数値が0であるか否か (zero? 0)#t
null ? リストが空リストかどうか (null? '())#t
empty? 入力されたリストが空か否か (empty? '())#t
void? void型かどうか (void? (set! a 3))#t

重要事項

  • (zero? <DATA>) : <DATA>が数値以外の場合はエラー
  • (null? <DATA>) : 引数が '()(空リスト)かどうかを確認する関数。リスト型以外は#f
  • (empty? <DATA>) : 引数のリストが '()空かどうかを確認する関数。リスト型以外は#f
  • (void? <DATA>) : 引数が void型かどうかを確認するための関数

リスト型とともに使われる関数として、null?や empty?があります。とくに null?はリストの終端チェックによく使われます。

zero?

使用方法: (zero? num)

zero?演算子は、数値が 0 であるかどうかをチェックします。

zero?
> (zero? 0)
#t
> (zero? 0.0)
#t
> (zero? -0)
#t
> (zero? 0.1)
#f
> (zero? "abc")  ; エラー
zero?: contract violation
  expected: number?
  given: "abc"

null?

使用方法: (null? lst)

null?演算子は、与えられたリストが、空リスト('())かチェックします。

null?
> (null? '())
#t
> (null? null)
#t
> (null? '(1 2))
#f
> (null? "abc")
#f

empty? : リストか空か、チェック

使用方法: (empty? lst)

empty?演算子は、与えられたリストが空であるかどうかをチェックします。

empty?
> (empty? '())
#t
> (empty null)
#t
> (empty? '(1 2))
#f
> (empty? "abc")
#f

void? : 引数がvoid型かチェック

使用方法: (void? obj)

void?演算子は、引数がvoid型であるかどうかをチェックします。

null?
> (void? (display ""))
#t
> (void? 1)
#f
> (void? (+ 1 2))
#f

さいごに

この記事では、Racket での比較演算子について紹介しました。条件分岐やや繰り返しなどで比較演算を使うことは、プログラミングの基本的な操作です。

この記事で紹介した演算子や関数を活用することで、実際的な Racket プログラムを作成できます。より高度なプログラミングになると比較演算はより複雑になっていきますので、関数型言語において比較演算を適切に使いこなせるよう、継続的に学習を進めていきましょう。

それでは、Happy Hacking!

参考資料

Web

脚注
  1. LISP: LISt Processing の略語で、リストを操作することができるプログラミング言語。 ↩︎

  2. 関数型言語: プログラムを数学的な関数の集合として考えるプログラミングパラダイムの 1つ。副作用を排除することで、プログラムの信頼性や並列処理の実現が可能となる。 ↩︎

  3. 複合データ型: リスト型、ベクター型のような複数のデータをまとめたデータ型 ↩︎

GitHubで編集を提案

Discussion