このブログ記事では、Haskellの重要な概念である関数、型、およびバインディングについて紹介します。

関数
さあ、早速コーディングを始めましょう。関数はHaskellの基本であり、次のように定義することができます
name arg1 arg2 ... argn = <expr>
ここで、name
は関数の名前、arg1 arg2 ... argn
は関数の引数/入力、<expr>
は関数の式です。ここで重要な点は、
HaskellにおけるreturnがPythonなど他のプログラミング言語で見るreturnと同じではないことです。定義した関数を使用するときは、
以下のようにします。
name arg1 arg2 ... argn
例
関数がどのようにHaskellで動作するかを体験するために、例を試してみましょう。以下の関数 double
と inRange
は、入力を倍にし、
与えられた範囲内に値があるかどうかを見ます。
double x = 2 * x
double 2 --- => 4
double 100 --- => 200
inRange min max x = min <= x && x <= max
inRange 10 15 11 --- => True
inRange 1 2 3 --- => False
これらをあなたのhsファイルに定義し、GHCiで関数を実行してみてください。
型
もしも上記の関数をVSCodeでHaskell拡張機能を使って定義した場合(もしまだしていない場合は、 Road to Haskeller #0 - Setting Up Environment を読んで同じ環境をセットアップすることをお勧めします)、関数の上に小さな文字列が表示されるはずです。それらは関数の推論された型ですが、 今はクリックしないでください。Haskellではすべての値(関数も値です)に型があり、次のように型を付けることができます。
x :: <type>
例
型がどのようにHaskellで付けられるかを理解するために、いくつかの例を見てみましょう。
x :: Integer
x = 1
y :: Bool
y = True
上記は変数に型を割り当てる方法を示しています。では、double
と inRange
にどのように型を割り当てるか見てみましょう。
double :: Integer -> Integer
double 1 --- => 2
double 1.2 --- => Type Error
inRange :: Float -> Float -> Float -> Bool
inRange 1.1 1.3 1.2 --- => True
inRange 1 3 2 --- => Type Error
まず double
関数を見てみましょう。型定義の最初の部分は、入力がInteger
型(1、2、3など)であることを指定します。
その後、出力もInteger
型であることを定義しています。ここで注意すべき点は、型定義では入力と出力を区別しないことです。
これはHaskellの非常に重要な概念(カリー化)に関連していますが、これについては後の記事で詳しく説明します。
inRange
関数についても同様です。最初の3つの引数の型はFloat
に設定され、出力はBool
(True
またはFalse
)に設定されています。
ただし、同じVSCodeのセットアップを使用している場合、上記と推論された型との違いについて疑問に思うかもしれません。これは推論された型が型クラス
(NumやOrdなど
)の概念を使用しているためですが、これについてはこの記事の範囲外です。今のところ、型クラスではなく具体的な型を使用することをお勧めします。
Bindings
時には、コードを整理するために何らかの中間変数を使用したいと思うことがあります。しかし、以下のような方法はHaskellでは許されていません。
inRange min max x =
lower_bound = x >= min
upper_bound = x <= max
return lower_bound && upper_bound
では、どうすればHaskellに叱られることなく同じことができるのでしょうか?ここでバインディングの出番です。
Letバインディング
let
バインディングは次のように機能します。
inRange min max x =
let lower_bound = x >= min
upper_bound = x <= max
in
lower_bound && upper_bound
ここで、let
を使って中間変数を定義し、in
でそれらの変数を操作します。
Whereバインディング
関数によっては、コードの可読性を向上させるために where
バインディングを使用したい場合があります。
inRange min max x = lower_bound && upper_bound
where lower_bound = x >= min
upper_bound = x <= max
ここでは、まず中間変数を操作し、その後にwhere
を使ってそれらの変数の意味を定義します。
If文
他のプログラミング言語でコーディングの経験がある場合、if 文をどのように書くかが気になるかもしれません。Haskellでは以下のように書くことができます。
inRange min max x =
if lower_bound then upper_bound else False
where lower_bound = x >= min
upper_bound = x <= max
これは非常に直感的で書きやすく、読みやすい方法です。今日は、Haskellにおける関数、型、バインディング、およびif文という重要な要素をカバーしました。
クイズ
この記事では、学習した内容を確認するためのクイズを設けます。記事のメイン部分を読んだ後に、ぜひ自分で問題を解いてみることを強くお勧めします。各問題をクリックすると答えが表示されます。
リソース
- Philipp, Hagenlocher. 2020. Haskell for Imperative Programmers #2 - Functions, Types, let & where. YouTube.