Haskell-quick-guide
Haskell-概要
Haskellは、記号計算およびリスト処理アプリケーションを処理するために特別に設計された関数型プログラミング言語です。 関数型プログラミングは数学関数に基づいています。 Haskell以外にも、関数型プログラミングのパラダイムに従う他の一般的な言語には、Lisp、Python、Erlang、Racket、F#、Clojureなどがあります。
- 従来のプログラミング*では、命令は特定の構文または形式の宣言のセットとして扱われますが、*機能的なプログラミング*の場合、すべての計算は個別の数学関数の組み合わせと見なされます。
Haskellで機能する
Haskellは、広く使用されている純粋に機能的な言語です。 ここで、この言語をJava、C、C ++、PHPなどの他の従来のプログラミング言語よりも特別なものにするいくつかのポイントをリストアップしました。
- 関数型言語-従来のプログラミング言語では、コンパイラに一連のタスクを指示します。これらのタスクは、コンピュータに「何をするか」および「どのように行うか」を伝えることです。しかし、Haskellでは、コンピューターに「それは何ですか?」
- *怠azine *-Haskellは怠zyな言語です。 *怠y *とは、Haskellが理由なしに式を評価しないことを意味します。 評価エンジンは、式を評価する必要があると判断すると、*サンクデータ構造*を作成して、その特定の評価に必要なすべての情報とその*サンクデータ構造*へのポインタを収集します。 評価エンジンは、その特定の式を評価する必要がある場合にのみ機能を開始します。
- モジュール性-Haskellアプリケーションは、一連の機能に他なりません。 Haskellアプリケーションは、多数の小さなHaskellアプリケーションのコレクションであると言えます。
- Statically Typed -従来のプログラミング言語では、一連の変数とそのタイプを定義する必要があります。 対照的に、Haskellは厳密に型指定された言語です。 用語「厳密に型指定された言語」とは、Haskellコンパイラーが宣言された変数の型を把握するのに十分にインテリジェントであることを意味します。したがって、使用される変数の型を明示的に述べる必要はありません。
- 保守性-Haskellアプリケーションはモジュール式であるため、保守が非常に簡単で費用対効果に優れています。
機能的プログラムはより並行的であり、実行時の並列性に従ってより正確で優れたパフォーマンスを提供します。 Haskellも例外ではありません。 *マルチスレッド*を効果的に処理する方法で開発されました。
こんにちは世界
Haskellのダイナミズムを示す簡単な例です。 次のコードを見てください。 必要なのは、コンソールに「Hello Word」を印刷する1行だけです。
Haskellコンパイラが上記のコードに遭遇すると、すぐに次の出力を生成します-
Haskellのパワーとシンプルさを示すために、このチュートリアル全体で多くの例を提供します。
Haskell-環境のセットアップ
Haskellプログラミング環境をオンラインでセットアップしました-https://www.finddevguides.com/compile_haskell_online.php
このオンラインエディターには、Haskellプログラミングの例を練習するためのオプションがたくさんあります。 ページの端末セクションに移動し、 "ghci" と入力します。 このコマンドはHaskellコンパイラを自動的にロードし、Haskellをオンラインで起動します。 ghci コマンドを使用すると、次の出力が表示されます。
それでもローカルシステムでHaskellをオフラインで使用する場合は、利用可能なHaskellセットアップを公式Webページからダウンロードする必要があります-https://www.haskell.org/downloads
市場で入手可能な3つの異なるタイプの*インストーラー*があります-
- *最小インストーラー-GHC(Glasgow Haskell Compiler)、CABAL(アプリケーションとライブラリを構築するための共通アーキテクチャ)、およびスタックツールを提供します。
- Stack Installer -このインストーラーでは、GHCをマネージドトールチェーンのクロスプラットフォームでダウンロードできます。 必要なときにいつでもAPIツールを更新できるように、アプリケーションをグローバルにインストールします。 Haskell指向のすべての依存関係を自動的に解決します。
- * Haskellプラットフォーム*-これは、Haskellをインストールする最良の方法です。プラットフォーム全体をマシンにインストールし、特定の場所からインストールするからです。 このインストーラーは、上記の2つのインストーラーのように配布されません。
市場で入手可能なさまざまなタイプのインストーラーを見てきたので、マシンでそれらのインストーラーを使用する方法を見てみましょう。 このチュートリアルでは、Haskellプラットフォームインストーラーを使用して、システムにHaskellコンパイラをインストールします。
Windowsでの環境設定
WindowsコンピューターにHaskell環境をセットアップするには、公式Webサイトhttps://www.haskell.org/platform/windowslにアクセスし、カスタマイズ可能なアーキテクチャーに従ってインストーラーをダウンロードします。
システムのアーキテクチャを確認し、対応するセットアップファイルをダウンロードして実行します。 他のWindowsアプリケーションと同様にインストールされます。 システムのCABAL構成を更新する必要がある場合があります。
MACで設定される環境
MACシステムにHaskell環境を設定するには、公式Webサイトhttps://www.haskell.org/platform/maclにアクセスして、Macインストーラーをダウンロードします。
Linuxでの環境設定
LinuxベースのシステムにHaskellをインストールするには、MACやWindowsのようにそれほど簡単ではないコマンドを実行する必要があります。 はい、面倒ですが、信頼できます。
以下の手順に従って、LinuxシステムにHaskellをインストールできます-
- ステップ1 *-LinuxシステムにHaskell環境をセットアップするには、公式Webサイトhttps://www.haskell.org/platform/linuxlにアクセスして、ディストリビューションを選択します。 ブラウザに次の画面が表示されます。
- ステップ2 *-ディストリビューションを選択します。 この例では、Ubuntuを使用しています。 このオプションを選択すると、ローカルシステムにHaskellをインストールするコマンドを含む画面に次のページが表示されます。
ステップ3 *-Ctrl + Alt + Tを押してターミナルを開きます。 *"$ sudo apt-get install haskell-platform" コマンドを実行し、Enterを押します。 rootパスワードで認証すると、システムにHaskellのダウンロードが自動的に開始されます。 インストール後、確認メッセージが表示されます。
- ステップ4 *-再度ターミナルに移動して、GHCIコマンドを実行します。 Preludeプロンプトが表示されたら、ローカルシステムでHaskellを使用する準備ができています。
GHCIプロローグを終了するには、コマンド「:quit exit」を使用できます。
Haskell-基本的なデータモデル
Haskellは純粋に機能的なプログラミング言語であるため、他のプログラミング言語よりもはるかにインタラクティブでインテリジェントです。 この章では、実際に事前定義されているか、何らかの形でインテリジェントにコンピューターのメモリにデコードされているHaskellの基本データモデルについて学びます。
このチュートリアルでは、Webサイト(https://www.finddevguides.com/codingground)から入手できるHaskellオンラインプラットフォームを使用します。
番号
Haskellは、ある数を数としてデコードするのに十分なインテリジェントです。 したがって、他のプログラミング言語の場合に通常行うように、そのタイプを外部で言及する必要はありません。 例として、プレリュードコマンドプロンプトに移動し、「2 + 2」を実行してEnterキーを押します。
その結果、次の出力が表示されます。
上記のコードでは、2つの数値を引数としてGHCIコンパイラーに型を事前定義せずに渡しましたが、コンパイラーはこれら2つのエントリを数値として簡単にデコードできました。
次に、もう少し複雑な数学的計算を試して、インテリジェントコンパイラが正しい出力を提供するかどうかを確認しましょう。 「15+(5 * 5)-40」で試してください
上記の式では、予想される出力に従って「0」が生成されます。
キャラクター
数字と同様に、Haskellは入力された文字をインテリジェントに識別できます。 Haskellコマンドプロンプトに移動し、二重引用符または一重引用符で任意の文字を入力します。
次の行を入力として提供し、その出力を確認しましょう。
それは次の出力を生成します-
入力の提供中に(: t )を使用することを忘れないでください。 上記の例では、*(:t)*は入力に関連する特定のタイプを含めることです。 このタイプの詳細については、今後の章で説明します。
次の例を見てください。ここでは、無効な入力をcharとして渡しているため、エラーが発生します。
エラーメッセージ "<interactive>:4:1:Not in scope:` a '"により、Haskellコンパイラは入力を認識できないことを警告しています。 Haskellは、すべてが数字を使用して表されるタイプの言語です。
Haskellは、従来のASCIIエンコーディングスタイルに従います。 もっと理解するために次の例を見てみましょう-
入力がどのようにASCII形式にデコードされるかを確認してください。
ひも
文字列「finddevguides.com」を渡す次の例を見てください。
画面に次の出力が生成されます-
文字列全体がCharの配列としてのみデコードされている方法を確認してください。 他のデータ型とその構文に移りましょう。 実際の練習を開始すると、すべてのデータ型とその使用法に慣れます。
ブール値
ブールデータ型も、他のデータ型と同様に非常に簡単です。 「True」や「False」などのブール入力を使用してさまざまなブール演算を使用する次の例を見てください。
上記の例では、「True」と「False」がブール値であることに言及する必要はありません。 Haskell自体がそれをデコードし、それぞれの操作を実行できます。 「true」または「false」で入力を変更しましょう。
それは次の出力を生成します-
上記の例では、Haskellは「true」と数値を区別できなかったため、入力された「true」は数値ではありません。 したがって、Haskellコンパイラは、入力がスコープではないことを示すエラーをスローします。
リストとリストの理解
他のデータ型と同様、 List もHaskellで使用される非常に便利なデータ型です。 例として、[a、b、c]は文字のリストです。したがって、定義により、Listはコンマで区切られた同じデータ型のコレクションです。
他のデータ型と同様に、リストをリストとして宣言する必要はありません。 Haskellは、式で使用されている構文を調べることで入力をデコードするのに十分インテリジェントです。
Haskellがリストをどのように扱うかを示す次の例を見てください。
それは次の出力を生成します-
Haskellのリストは本質的に同質です。つまり、異なる種類のデータ型のリストを宣言することはできません。 [1,2,3,4,5、a、b、c、d、e、f]のようなリストはエラーを生成します。
このコードは、次のエラーを生成します-
リストの理解
リストの理解は、数式を使用してリストを生成するプロセスです。 次の例を見てください。ここでは、[output |範囲、条件]。
数式を使用して1つのリストを作成するこの方法は、*リスト内包*と呼ばれます。
タプル
Haskellは、単一のデータ型で複数の値を宣言する別の方法を提供します。 Tuple として知られています。 タプルはリストと見なすことができますが、タプルとリストの間にはいくつかの技術的な違いがあります。
リストは変更可能なデータ型ですが、実行時に要素の数を変更できないため、タプルは不変のデータ型です。
一方、リストは同種のデータ型ですが、タプルには異種のデータが含まれている可能性があるため、タプルは本質的に異種です。
タプルは単一の括弧で表されます。 次の例を見て、Haskellがタプルをどのように扱うかを確認してください。
それは次の出力を生成します-
上記の例では、2つの number 型変数と1つの char 型変数を持つ1つのTupleを使用しました。
Haskell-基本的な演算子
この章では、Haskellで使用されるさまざまな演算子について学びます。 他のプログラミング言語と同様に、Haskellは加算、減算、乗算などの基本的な操作をインテリジェントに処理します。 今後の章では、さまざまな演算子とその使用法について詳しく学習します。
この章では、オンラインプラットフォーム(https://www.finddevguides.com/codingground)を使用して、Haskellでさまざまな演算子を使用します。 整数*型番号のみを使用していることに注意してください。これは、後続の章で 10進数*型番号について詳しく学習するためです。
加算演算子
名前が示すように、加算(+)演算子は加算機能に使用されます。 次のサンプルコードは、Haskellで2つの整数を追加する方法を示しています-
上記のファイルでは、2つの別個の変数 var1 および var2 を作成しました。 最後に、 addition 演算子を使用して結果を出力します。 compile および execute ボタンを使用して、コードを実行します。
このコードは、画面に次の出力を生成します-
減算演算子
名前が示すように、この演算子は減算演算に使用されます。 次のサンプルコードは、Haskellで2つの整数を減算する方法を示しています-
この例では、2つの変数 var1 および var2 を作成しました。 その後、減算(-)演算子を使用して2つの値を減算します。
このコードは、画面に次の出力を生成します-
乗算演算子
この演算子は乗算演算に使用されます。 次のコードは、乗算演算子を使用してHaskellで2つの数値を乗算する方法を示しています-
このコードは、オンラインプラットフォームで実行すると、次の出力を生成します-
除算演算子
次のコードを見てください。 Haskellで2つの数値を分割する方法を示しています-
それは次の出力を生成します-
シーケンス/範囲演算子
シーケンスまたは範囲は、Haskellの特別な演算子です。 「(..)」で示されます。 値のシーケンスを含むリストを宣言するときに、この演算子を使用できます。
1から10までのすべての値を印刷する場合、「[1..10]」のようなものを使用できます。 同様に、「a」から「z」までのすべてのアルファベットを生成する場合は、 "[a..z]" と入力するだけです。
次のコードは、シーケンス演算子を使用して1から10までのすべての値を印刷する方法を示しています-
それは次の出力を生成します-
Haskell-意思決定
意思決定は、プログラマーがコードフローに条件を適用できるようにする機能です。 プログラマは、事前定義された条件に応じて一連の命令を実行できます。 次のフローチャートは、Haskellの意思決定構造を示しています-
Haskellは、意思決定ステートメントの次のタイプを提供します-
Sr.No. | Statement & Description |
---|---|
1 |
|
2 |
複数の if ブロックとそれに続く else ブロック |
Haskell-型と型クラス
Haskellは関数型言語であり、厳密に型指定されています。つまり、アプリケーション全体で使用されるデータ型は、コンパイル時にコンパイラーに認識されます。
組み込み型クラス
Haskellでは、すべてのステートメントは数式と見なされ、この式のカテゴリは Type と呼ばれます。 「タイプ」は、コンパイル時に使用される式のデータ型であると言えます。
Int
ここでは、関数* fType()のタイプを *int として設定しています。 この関数は2つの int 値を取り、1つの int 値を返します。 このコードをコンパイルして実行すると、次の出力が生成されます-
整数
整数*は *Int のスーパーセットと見なすことができます。 この値は任意の数に制限されていないため、整数の長さには制限がありません。 Int 型と Integer 型の基本的な違いを確認するには、次のように上記のコードを変更しましょう-
上記のコードをコンパイルすると、次のエラーメッセージがスローされます-
このエラーは、関数fType()が1つのInt型値を予期しており、実際の大きなInt型値を渡すために発生しました。 このエラーを回避するには、タイプ「Int」を「Integer」で変更し、違いを観察しましょう。
今、それは次の出力を生成します-
浮く
次のコードをご覧ください。 HaskellでのFloat型の動作を示しています-
この関数は、入力として2つの浮動小数点値を取り、出力として別の浮動小数点値を生成します。 このコードをコンパイルして実行すると、次の出力が生成されます-
ダブル
上記のコードを実行すると、次の出力が生成されます-
Bool
ここでは、変数 "x"をBoolとして定義し、別のブール値と比較してその独自性を確認しています。 それは次の出力を生成します-
Char
Charはキャラクターを表します。 一重引用符内のすべては、キャラクターと見なされます。 次のコードでは、Char値を受け入れ、出力としてChar値を返すように、以前の* fType()*関数を変更しました。
上記のコードは、 char 値 'v’で* fType()*関数を呼び出しますが、別のchar値、つまり 'K’を返します。 ここにその出力があります-
Haskellは型が宣言される前にその型をキャッチするのに十分なインテリジェントであるため、これらの型を明示的に使用しないことに注意してください。 このチュートリアルの以降の章では、異なる型とTypeクラスがHaskellを強く型付けされた言語にする方法を説明します。
EQタイプクラス
上記のすべての標準Typeクラスは、この EQ クラスの一部です。 上記の型のいずれかを使用して同等性をチェックするときはいつでも、実際には EQ 型クラスを呼び出しています。
次の例では、内部で「==」または「/=」操作を使用して EQ タイプを使用しています。
次の出力が得られます-
順序型クラス
このタイプクラスの「比較」機能を使用した例を以下に示します。
ここで、Haskellコンパイラは4が2以下かどうかをチェックします。 そうではないので、コードは次の出力を生成します-
Show
コンソールに次の出力が生成されます。 ここで、二重引用符は、文字列型の値であることを示しています。
Read
ここでは、ストリング変数( "12")を readInt メソッドに渡し、変換後に12(Int値)を返します。 ここにその出力があります-
Enum
次のコードは、12の後続値を見つける方法を示しています。
それは次の出力を生成します-
跳ねる
上限と下限を持つすべてのタイプは、このタイプクラスに属します。 たとえば、 Int タイプのデータには、「9223372036854775807」の上限と「-9223372036854775808」の下限があります。
次のコードは、HaskellがInt型の最大および最小境界を決定する方法を示しています。
それは次の出力を生成します-
次に、Char、Float、およびBool型の最大および最小境界を見つけてみてください。
Num
この型クラスは数値演算に使用されます。 Int、Integer、Float、Doubleなどの型は、このTypeクラスの下にあります。 次のコードを見てください-
それは次の出力を生成します-
積分
フローティング
Integralと同様に、FloatingもNum Typeクラスの一部ですが、浮動小数点数のみを保持します。 したがって、 Float と Double はこの型クラスの下にあります。
カスタムタイプクラス
他のプログラミング言語と同様に、Haskellでは開発者がユーザー定義型を定義できます。 次の例では、ユーザー定義型を作成して使用します。
ここでは、 Area という新しいタイプを作成しました。 次に、このタイプを使用して円の面積を計算しています。 上記の例では、「surface」は入力として Area を取り、出力として Float を生成する関数です。
ここで「データ」はキーワードであり、Haskellのすべてのユーザー定義型は常に大文字で始まることに注意してください。
それは次の出力を生成します-
Haskell-関数
Haskellは関数型プログラミング言語であるため、関数は主要な役割を果たします。 他の言語と同様に、Haskellには独自の機能定義と宣言があります。
- 関数宣言は、関数名と引数リストとその出力で構成されます。
- 関数定義は、実際に関数を定義する場所です。
この概念を詳細に理解するために、 add 関数の小さな例を取り上げましょう。
ここでは、1行目で関数を宣言し、2行目で2つの引数を取り、1つの整数型の出力を生成する実際の関数を記述しました。
他のほとんどの言語と同様に、Haskellは main メソッドからコードのコンパイルを開始します。 私たちのコードは次の出力を生成します-
パターンマッチング
パターンマッチングは、特定の種類の式を照合するプロセスです。 これは、コードを単純化するためのテクニックにすぎません。 この手法は、任意のタイプのTypeクラスに実装できます。 If-Elseは、パターンマッチングの代替オプションとして使用できます。
パターンマッチングは、実行時に引数リストに応じてさまざまなメソッドを実行できる動的なポリモーフィズムのバリアントと見なすことができます。
次のコードブロックを見てください。 ここでは、パターンマッチングの手法を使用して、数値の階乗を計算しました。
数の階乗を計算する方法はすべて知っています。 コンパイラーは、引数を持つ「ファクト」と呼ばれる関数の検索を開始します。 引数が0に等しくない場合、数値は同じ関数を呼び出し続けますが、実際の引数よりも1少ない値になります。
引数のパターンが0と完全に一致すると、「ファクト0 = 1」であるパターンを呼び出します。 私たちのコードは次の出力を生成します-
警備員
次のコードでは、 guards の概念を使用して factorial プログラムを変更しました。
ここでは、「|」で区切られた2つの*ガード*を宣言しましたそして main から fact 関数を呼び出します。 内部的には、コンパイラはパターンマッチングの場合と同じように動作して、次の出力を生成します-
Where句
入力が複数のパラメーターを持つ複雑な式であるシナリオを考えます。 そのような場合、「where」節を使用して式全体を小さな部分に分割できます。
次の例では、複雑な数式を使用しています。 Haskellを使用して多項式方程式[x ^ 2-8x + 6]の根を見つける方法を示します。
与えられた多項式関数の根を計算する式の複雑さに注意してください。 かなり複雑です。 したがって、 where 句を使用して式を壊しています。 上記のコードは次の出力を生成します-
再帰関数
再帰は、関数がそれ自体を繰り返し呼び出す状況です。 Haskellは、式を複数回ループする機能を提供しません。 代わりに、Haskellは、機能全体をさまざまな機能のコレクションに分割し、再帰手法を使用して機能を実装することを望んでいます。
数値の階乗を計算したパターンマッチングの例をもう一度考えてみましょう。 数値の階乗を見つけることは、再帰を使用する典型的なケースです。 ここで、「パターンマッチングは再帰とどのように違うのでしょうか?」これら2つの違いは、使用方法にあります。 再帰は関数呼び出しであるのに対して、パターンマッチングは端末制約の設定で機能します。
次の例では、パターンマッチングと再帰の両方を使用して、5の階乗を計算しています。
それは次の出力を生成します-
高階関数
これまでに見てきたことは、Haskell関数が1つの type を入力として受け取り、別の type を出力として生成することです。これは、他の命令型言語とほとんど同じです。 高階関数は、関数を入力または出力引数として使用できるHaskellのユニークな機能です。
これは仮想概念ですが、実際のプログラムでは、Haskellで定義するすべての関数は高次メカニズムを使用して出力を提供します。 Haskellのライブラリ関数を調べる機会があれば、ほとんどのライブラリ関数がより高次の方法で記述されていることがわかります。
組み込みの高次関数マップをインポートし、それを使用して選択に応じて別の高次関数マップを実装する例を見てみましょう。
上記の例では、Type Class Char の toUpper 関数を使用して、入力を大文字に変換しました。 ここで、メソッド「map」は引数として関数を取り、必要な出力を返しています。 ここにその出力があります-
ラムダ式
アプリケーションの寿命全体を通して、一度だけ使用される関数を作成する必要がある場合があります。 このような状況に対処するために、Haskell開発者は lambda expression または lambda function として知られる別の匿名ブロックを使用します。
定義のない関数は、ラムダ関数と呼ばれます。 ラムダ関数は、「\」文字で示されます。 関数を作成せずに入力値を1増やす次の例を見てみましょう。
ここでは、名前のない匿名関数を作成しました。 引数として整数4を取り、出力値を出力します。 基本的に、適切に宣言することなく、1つの関数を操作しています。 それがラムダ式の美しさです。
私たちのラムダ式は、次の出力を生成します-
Haskell-関数の詳細
ここまで、多くの種類のHaskell関数について説明し、それらの関数を呼び出すためのさまざまな方法を使用しました。 この章では、特別なTypeクラスをインポートせずにHaskellで簡単に使用できるいくつかの基本的な関数について学びます。 これらの関数のほとんどは、他の高次関数の一部です。
ヘッド機能
それは次の出力を生成します-
テール機能
それは次の出力を生成します-
最後の機能
名前が示すように、入力として提供されるリストの最後の要素を生成します。 次の例を確認してください。
それは次の出力を生成します-
初期化関数
今、その出力を観察します-
ヌル関数
それは次の出力を生成します-
逆機能
String入力で機能し、入力全体を逆順に変換し、結果として1つの出力を提供します。 以下は、この関数のコードベースです。
それは次の出力を生成します-
長さ関数
この関数は、引数として指定された list の長さを計算するために使用されます。 次の例を見てください-
リストには10個の要素があるため、出力として10のコードが生成されます。
機能を取る
コードは、提供されたリストから5つの要素を含む部分文字列を生成します-
ドロップ機能
この関数は、部分文字列の生成にも使用されます。 take 関数の反対として機能します。 次のコードを見てください-
コードは、指定されたリストから最初の5つの要素を削除し、残りの5つの要素を出力します。 それは次の出力を生成します-
最大機能
この関数は、指定されたリストから最大値を持つ要素を見つけるために使用されます。 実際にそれを使用する方法を見てみましょう-
上記のコードは次の出力を生成します-
最小関数
この関数は、指定されたリストから最小値を持つ要素を見つけるために使用されます。 これは*最大*関数の反対です。
上記のコードの出力は-
和関数
名前が示すように、この関数は指定されたリストに存在するすべての要素の合計を返します。 次のコードは、5つの要素のリストを受け取り、その合計を出力として返します。
それは次の出力を生成します-
製品の機能
この関数を使用して、リスト内のすべての要素を乗算し、その値を出力できます。
私たちのコードは次の出力を生成します-
エレム関数
この関数は、指定されたリストに特定の要素が含まれているかどうかを確認するために使用されます。 したがって、 true または false を返します。
次のコードは、指定された要素のリストに値786が含まれているかどうかを確認します。
それは次の出力を生成します-
同じコードを使用して、提供されたリストに値1785が含まれているかどうかを確認します。
Haskell-関数の構成
関数構成*は、ある関数の出力を別の関数の入力として使用するプロセスです。 *組成*の背後にある数学を学べばもっと良いでしょう。 数学では、 *composition は f \ {g(x)} で示されます。ここで、* g()は関数であり、その出力は別の関数の入力、つまり f()*です。
関数合成は、1つの関数の出力タイプが2番目の関数の入力タイプと一致する場合、任意の2つの関数を使用して実装できます。 Haskellで関数構成を実装するには、ドット演算子(。)を使用します。
次のサンプルコードをご覧ください。 ここでは、関数合成を使用して、入力数が偶数か奇数かを計算しました。
ここで、 main 関数では、 noto と eveno の2つの関数を同時に呼び出しています。 コンパイラーは、最初に 16 を引数として関数 "eveno()" を呼び出します。 その後、コンパイラは eveno メソッドの出力を* noto()*メソッドの入力として使用します。
その出力は次のようになります-
入力として16(偶数)を指定しているため、* eveno()関数は *true を返し、これは* noto()*関数の入力になり、出力を返します。「これは偶数」。
Haskell-モジュール
Javaで作業したことがある場合は、 package というフォルダーにすべてのクラスがどのようにバインドされているかがわかります。 同様に、Haskellは*モジュール*のコレクションと考えることができます。
Haskellは関数型言語であり、すべてが式として示されているため、モジュールは類似または関連するタイプの関数のコレクションとして呼び出すことができます。
1つのモジュールから別のモジュールに関数を*インポート*できます。 他の関数の定義を開始する前に、すべての「import」ステートメントが最初に来るはずです。 この章では、Haskellモジュールのさまざまな機能について学びます。
リストモジュール
次の例では、Listモジュールで使用可能ないくつかの重要な機能を使用しています。
ここでは、多くの関数を定義せずに使用しています。 これは、これらの関数がリストモジュールで使用できるためです。 Listモジュールをインポートした後、Haskellコンパイラーはこれらすべての関数をグローバル名前空間で利用可能にしました。 したがって、これらの関数を使用できます。
私たちのコードは次の出力を生成します-
チャーモジュール
ここで、関数 toUpper および toLower は Char モジュール内で既に定義されています。 それは次の出力を生成します-
マップモジュール
それは次の出力を生成します-
セットモジュール
Setモジュールには、数学データを操作するための非常に便利な定義済み関数がいくつかあります。 セットはバイナリツリーとして実装されるため、セット内のすべての要素は一意である必要があります。
次のサンプルコードを見てください
ここでは、StringをSetに変更しています。 次の出力が生成されます。 出力セットに文字の繰り返しがないことを確認してください。
カスタムモジュール
他のプログラムで呼び出すことができるカスタムモジュールを作成する方法を見てみましょう。 このカスタムモジュールを実装するには、 "main.hs" とともに "custom.hs" という別のファイルを作成します。
カスタムモジュールを作成し、その中にいくつかの関数を定義しましょう。
custom.hs
カスタムモジュールの準備ができました。 次に、プログラムにインポートします。
main.hs
私たちのコードは次の出力を生成します-
「4」は偶数なので、 showEven 関数は True を返します。 showBoolean 関数は、関数に渡したブール関数が「True」であるため、「1」を返します。
Haskell-入力および出力
これまでに説明したすべての例は、本質的に静的です。 この章では、ユーザーと動的に通信する方法を学びます。 Haskellで使用されるさまざまな入力および出力テクニックを学びます。
ファイルとストリーム
これまで、プログラム自体のすべての入力をハードコーディングしました。 静的変数から入力を取得しています。 次に、外部ファイルからの読み取りおよび書き込みの方法を学びましょう。
ファイルを作成して、「abc.txt」という名前を付けましょう。 次に、このテキストファイルに「Welcome to finddevguides。 ここでは、Haskellを学ぶのに最適なリソースを入手できます。」
次に、このファイルの内容をコンソールに表示する次のコードを記述します。 ここでは、EOF文字が見つかるまでファイルを読み取る関数readFile()を使用しています。
上記のコードは、「abc.txt」というファイルを文字列として読み取り、ファイルの終わり文字が見つかるまで読み取ります。 このコードは次の出力を生成します。
端末で印刷しているものはすべて、そのファイルに書き込まれていることを確認します。
コマンドライン引数
Haskellは、コマンドプロンプトからファイルを操作する機能も提供します。 ターミナルに戻り、 "ghci" と入力しましょう。 次に、コマンドの次のセットを入力します-
ここでは、「abc.txt」というテキストファイルを作成しました。 次に、コマンド writeFile を使用して、ファイルにステートメントを挿入しました。 最後に、コマンド readFile を使用して、コンソールにファイルの内容を印刷しました。 私たちのコードは次の出力を生成します-
例外
- 例外*はコードのバグとみなすことができます。 これは、コンパイラーが実行時に期待される出力を取得しない状況です。 他の優れたプログラミング言語と同様に、Haskellは例外処理を実装する方法を提供します。
Javaに精通している場合は、Try-Catchブロックを知っているかもしれません。通常はエラーをスローし、 catch ブロックで同じエラーをキャッチします。 Haskellには、ランタイムエラーをキャッチするための同じ関数もあります。
- try の関数定義は、「try
- Exception e ⇒ IO a→ IO(e e e a)」のようになります。 次のサンプルコードをご覧ください。 「ゼロ除算」例外をキャッチする方法を示しています。
上記の例では、 Control.Exception モジュールの組み込みの try 関数を使用しているため、事前に例外をキャッチしています。 上記のコードは、画面に以下の出力を生成します。
ハスケル-ファンクター
Haskellの Functor は、さまざまなタイプの機能表現の一種であり、マッピングできます。 これは、ポリモーフィズムを実装するための高レベルの概念です。 Haskell開発者によると、リスト、マップ、ツリーなどのすべてのタイプ Haskell Functorのインスタンスです。
- ファンクター*は、次のような関数定義を持つ組み込みクラスです-
この定義により、 Functor は関数、たとえば* fmap()を取り、別の関数を返す関数であると結論付けることができます。 上記の例では、 fmap()は関数 map()*の一般化された表現です。
次の例では、Haskell Functorの動作を確認します。
ここでは、減算演算のリストで* map()と fmap()*の両方を使用しています。 両方のステートメントが、要素[1,3,7,15]を含むリストの同じ結果を生成することがわかります。
両方の関数が* subtract()*と呼ばれる別の関数を呼び出して結果を生成しました。
次に、 map と fmap の違いは何ですか?違いはそれらの使用法にあります。 Functor を使用すると、「just」や「Nothing」など、さまざまなデータ型の機能主義者を実装できます。
上記のコードは、端末に次の出力を生成します-
Applicative Functor
Applicative Functorは、Applicative Type Classによって提供されるいくつかの追加機能を備えた通常のFunctorです。
Functorを使用して、通常、既存の関数とその内部で定義された別の関数をマッピングします。 ただし、Functor内で定義された関数を別のFunctorにマップする方法はありません。 そのため、 Applicative Functor という別の機能があります。 このマッピング機能は、 Control モジュールの下で定義されたApplicative Typeクラスによって実装されます。 このクラスでは、2つのメソッドのみを使用できます。1つは pure で、もう1つは* <*> *です。
以下は、Applicative Functorのクラス定義です。
実装によると、2つのメソッド "Pure" および* "<*>" *を使用して別のFunctorをマップできます。 「Pure」メソッドは任意のタイプの値を取る必要があり、常にその値のApplicative Functorを返します。
次の例は、Applicative Functorの仕組みを示しています-
ここでは、関数 f1 の関数呼び出しに適用可能なファンクターを実装しました。 私たちのプログラムは次の出力を生成します。
モノイド
Haskellがすべてを関数の形式で定義していることを知っています。 関数には、関数の出力として入力を取得するオプションがあります。 これが Monoid です。
モノイドのタイプクラスの定義を次に示します。
HaskellでのMonoidの使用を理解するには、次の例をご覧ください。
私たちのコードは次の出力を生成します-
ここで、関数「multi」は入力に「1」を乗算します。 同様に、関数「add」は入力に「0」を追加します。 どちらの場合も、出力は入力と同じになります。 したがって、関数* \ {()、1} *および *\ {(+)、0} はモノイドの完全な例です。
ハスケル-モナド
3つのルールはすべて、次のようなモナド宣言に厳密に適用されます-
モナド宣言に適用される3つの基本的な法則は次のとおりです-
- 左アイデンティティ法- return 関数は値を変更せず、Monadの何も変更しないでください。 「return> ⇒ mf = mf」と表現できます。
- Right Identity Law - return 関数は値を変更せず、Monadの何も変更すべきではありません。 「mf> ⇒ return = mf」と表現できます。
- 関連性-この法律によれば、ファンクターとモナドのインスタンスは同じように動作するはずです。 「(f> =⇒ g)> ⇒ h = f> ⇒(g> = h)」と数学的に表現できます。
最初の2つの法則は同じポイントを反復します。つまり、 return は bind 演算子の両側で恒等的な振る舞いを持つべきです。
モナドであることを認識せずに、前の例ですでに多くのモナドを使用しています。 List Monadを使用して特定のリストを生成する次の例を考えてみましょう。
このコードは、次の出力を生成します-
Haskell-ジッパー
Haskellの Zippers は、基本的に tree などのデータ構造の特定の場所を指すポインターです。
完全な二分木として表現できる5つの要素 [45,7,55,120,56] を持つ tree を考えてみましょう。 このリストの最後の要素を更新する場合は、すべての要素を走査して、更新する前に最後の要素に到達する必要があります。 右?
しかし、 N 要素を持つツリーが [(N-1)、N] のコレクションであるような方法でツリーを構築できたらどうでしょう。 次に、不要な*(N-1)*要素をすべて走査する必要はありません。 N番目の要素を直接更新できます。 これがまさにZipperのコンセプトです。 ツリー全体を走査せずにその値を更新できるツリーの特定の場所にフォーカスまたはポイントします。
次の例では、リストにZipperの概念を実装しています。 同様に、*ツリー*または*ファイル*データ構造にZipperを実装できます。
上記のプログラムをコンパイルして実行すると、次の出力が生成されます-
ここでは、前方または後方に向かって、弦全体の要素に注目しています。