Haskell-functions

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

Haskell-関数

Haskellは関数型プログラミング言語であるため、関数は主要な役割を果たします。 他の言語と同様に、Haskellには独自の機能定義と宣言があります。

  • 関数宣言は、関数名と引数リストとその出力で構成されます。
  • 関数定義は、実際に関数を定義する場所です。

この概念を詳細に理解するために、 add 関数の小さな例を取り上げましょう。

add :: Integer -> Integer -> Integer   --function declaration
add x y =  x + y                       --function definition

main = do
   putStrLn "The addition of the two numbers is:"
   print(add 2 5)    --calling a function

ここでは、1行目で関数を宣言し、2行目で2つの引数を取り、1つの整数型の出力を生成する実際の関数を記述しました。

他のほとんどの言語と同様に、Haskellは main メソッドからコードのコンパイルを開始します。 私たちのコードは次の出力を生成します-

The addition of the two numbers is:
7

パターンマッチング

パターンマッチングは、特定の種類の式を照合するプロセスです。 これは、コードを単純化するためのテクニックにすぎません。 この手法は、任意のタイプのTypeクラスに実装できます。 If-Elseは、パターンマッチングの代替オプションとして使用できます。

パターンマッチングは、実行時に引数リストに応じてさまざまなメソッドを実行できる動的なポリモーフィズムのバリアントと見なすことができます。

次のコードブロックを見てください。 ここでは、パターンマッチングの手法を使用して、数値の階乗を計算しました。

fact :: Int -> Int
fact 0 = 1
fact n = n * fact ( n - 1 )

main = do
   putStrLn "The factorial of 5 is:"
   print (fact 5)

数の階乗を計算する方法はすべて知っています。 コンパイラーは、引数を持つ「ファクト」と呼ばれる関数の検索を開始します。 引数が0に等しくない場合、数値は同じ関数を呼び出し続けますが、実際の引数よりも1少ない値になります。

引数のパターンが0と完全に一致すると、「ファクト0 = 1」であるパターンを呼び出します。 私たちのコードは次の出力を生成します-

The factorial of 5 is:
120

警備員

*Guards* は、パターンマッチングに非常によく似た概念です。 パターンマッチングでは、通常1つ以上の式を照合しますが、 *guards* を使用して式の一部のプロパティをテストします。
*guards* よりもパターンマッチングを使用することをお勧めしますが、開発者の観点からは、 *guards* はより読みやすく簡単です。 初めてのユーザーの場合、 *guards* はIf-Elseステートメントと非常によく似ていますが、機能的に異なります。

次のコードでは、 guards の概念を使用して factorial プログラムを変更しました。

fact :: Integer -> Integer
fact n | n == 0 = 1
       | n/= 0 = n * fact (n-1)
main = do
   putStrLn "The factorial of 5 is:"
   print (fact 5)

ここでは、「|」で区切られた2つの*ガード*を宣言しましたそして main から fact 関数を呼び出します。 内部的には、コンパイラはパターンマッチングの場合と同じように動作して、次の出力を生成します-

The factorial of 5 is:
120

Where句

*Where* は、実行時に目的の出力を生成するために使用できるキーワードまたは組み込み関数です。 関数の計算が複雑になる場合に非常に役立ちます。

入力が複数のパラメーターを持つ複雑な式であるシナリオを考えます。 そのような場合、「where」節を使用して式全体を小さな部分に分割できます。

次の例では、複雑な数式を使用しています。 Haskellを使用して多項式方程式[x ^ 2-8x + 6]の根を見つける方法を示します。

roots :: (Float, Float, Float) -> (Float, Float)
roots (a,b,c) = (x1, x2) where
   x1 = e + sqrt d/(2 *a)
   x2 = e - sqrt d/(2* a)
   d = b *b - 4* a *c
   e = - b/(2* a)
main = do
   putStrLn "The roots of our Polynomial equation are:"
   print (roots(1,-8,6))

与えられた多項式関数の根を計算する式の複雑さに注意してください。 かなり複雑です。 したがって、 where 句を使用して式を壊しています。 上記のコードは次の出力を生成します-

The roots of our Polynomial equation are:
(7.1622777,0.8377223)

再帰関数

再帰は、関数がそれ自体を繰り返し呼び出す状況です。 Haskellは、式を複数回ループする機能を提供しません。 代わりに、Haskellは、機能全体をさまざまな機能のコレクションに分割し、再帰手法を使用して機能を実装することを望んでいます。

数値の階乗を計算したパターンマッチングの例をもう一度考えてみましょう。 数値の階乗を見つけることは、再帰を使用する典型的なケースです。 ここで、「パターンマッチングは再帰とどのように違うのでしょうか?」これら2つの違いは、使用方法にあります。 再帰は関数呼び出しであるのに対して、パターンマッチングは端末制約の設定で機能します。

次の例では、パターンマッチングと再帰の両方を使用して、5の階乗を計算しています。

fact :: Int -> Int
fact 0 = 1
fact n = n * fact ( n - 1 )

main = do
   putStrLn "The factorial of 5 is:"
   print (fact 5)

それは次の出力を生成します-

The factorial of 5 is:
120

高階関数

これまでに見てきたことは、Haskell関数が1つの type を入力として受け取り、別の type を出力として生成することです。これは、他の命令型言語とほとんど同じです。 高階関数は、関数を入力または出力引数として使用できるHaskellのユニークな機能です。

これは仮想概念ですが、実際のプログラムでは、Haskellで定義するすべての関数は高次メカニズムを使用して出力を提供します。 Haskellのライブラリ関数を調べる機会があれば、ほとんどのライブラリ関数がより高次の方法で記述されていることがわかります。

組み込みの高次関数マップをインポートし、それを使用して選択に応じて別の高次関数マップを実装する例を見てみましょう。

import Data.Char
import Prelude hiding (map)

map :: (a -> b) -> [a] -> [b]
map _ [] = []
map func (x : abc) = func x : map func abc
main = print $ map toUpper "finddevguides.com"

上記の例では、Type Class ChartoUpper 関数を使用して、入力を大文字に変換しました。 ここで、メソッド「map」は引数として関数を取り、必要な出力を返しています。 ここにその出力があります-

sh-4.3$ ghc -O2 --make *.hs -o main -threaded -rtsopts
sh-4.3$ main
"finddevguides.COM"

ラムダ式

アプリケーションの寿命全体を通して、一度だけ使用される関数を作成する必要がある場合があります。 このような状況に対処するために、Haskell開発者は lambda expression または lambda function として知られる別の匿名ブロックを使用します。

定義のない関数は、ラムダ関数と呼ばれます。 ラムダ関数は、「\」文字で示されます。 関数を作成せずに入力値を1増やす次の例を見てみましょう。

main = do
   putStrLn "The successor of 4 is:"
   print ((\x -> x + 1) 4)

ここでは、名前のない匿名関数を作成しました。 引数として整数4を取り、出力値を出力します。 基本的に、適切に宣言することなく、1つの関数を操作しています。 それがラムダ式の美しさです。

私たちのラムダ式は、次の出力を生成します-

sh-4.3$ main
The successor of 4 is:
5