講義ノート「最初のプログラミング言語としてのHaskell」 パート2

こんにちはHabr! 今日は、関数の多相性、演算子、およびカリー化について説明します。 講義は初心者向けであり、概要では簡潔なプレゼンテーションを提案していることを思い出してください。 まだ興味があれば...



前編



多型


関数は、さまざまなタイプのデータを処理できる場合、多態的です。 最も単純な多相関数は恒等関数です:

id :: a -> a id x = x
      
      





ほとんどの場合、ポリモーフィズムはリストの操作に使用されます(これは理解できます)。

 length :: [a] -> Int length [] = 0 length (_:l) = 1 + length l
      
      





この関数のスコープ(明らかにリストの長さを計算する)は、タイプaの変数のリストです。 一般的な用語では、そのような設計は単に「アショクのリスト」と呼ばれます。 この関数は、入力として任意のリストを受け入れます。 プレリュードのほとんどの関数は多態的です。 怠けてはいけません-見てください。 それまでの間、別の例を次に示します。

 filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x:xs) | px = x : filter p xs | otherwise = filter p xs
      
      





フィルタ関数は、特定の条件を満たす要素のみをリストに残します。



ご覧のとおり、多相型は関数のドメインにもなります。

 error :: String -> a
      
      





この場合、エラー関数はエラーに関する入力文字列を受け取り、タイプaの変数を返します。

パラメータなしの多相関数は非常に興味深い定義がされています-未定義:

 undefined :: a undefined = error "Prelude.undefined"
      
      





この定数関数は、あらゆるタイプの不定の数量を示すために使用されます。



オペレーター


引数の間に配置できる関数は、インフィックスまたは単に演算子と呼ばれます。 (引数という言葉は条件付きで使用されますが、Haskellには2つの引数の関数がないことを覚えています)。

Haskell構文では、次の文字を使用してステートメントを構築できます。

":#$%* +-=。 / \ <>?! @ ^ | 」

演算子は、次の組み合わせを除き、好きなように構成できます。

":: = ...-@ \ | <-->〜=> "

演算子名が括弧で囲まれているという事実に加えて、関数定義は接頭辞表記と同じです。 例:

 (%%) :: Int -> Int -> (Int, Int) (%%) xy = (div xy, rem xy)
      
      





中置記法での関数の定義に加えて、多くの場合、演算子の優先度と結合性のタイプを示す必要があります。 Haskellでは、優先度は整数で与えられ、数値が大きいほど優先度が高くなり、ステートメントが早く実行されます。



結合性により、演算子は結合性、右側の結合性、左側の結合性、および非結合性に分けられます。

いくつかの条件演算子「\ /」:



Haskellの場合:



したがって、優先順位と結合性を考慮して、演算子を作成します。

 infixr 7 -- ,  7 (\/) :: Bool -> Bool -> Bool (\/) xy = ...
      
      







標準プレリュード演算子の優先度と結合性:

 infixr 9 . infixl 9 !! infixr 8 ^, ^^, ** infixl 7 *, /, `quot`, `rem`, `div`, `mod`, :%, % infixl 6 +, - infixr 5 :, ++ infix 4 ==, /=, <, <=, >=, >, `elem`, `notElem` infixr 3 && infixr 2 || infixl 1 >>, >>= infixr 1 =<< infixr 0 $, $!, `seq`
      
      





キャリング


では、なぜHaskellに2つ以上の引数の関数がないのですか? 機能を考えてみましょう:

 plus :: (Integer, Integer) -> Integer plus (x, y) = x + y
      
      





plus関数には引数が1つあります。 この引数は数値のペアです。

通常、Haskellの関数は次のように記述されます。

 plus :: Integer -> Integer -> Integer plus xy = x + y
      
      





また、この関数には1つの引数があり(考えられるように2つではありません)、この引数は整数型の数です。 したがって、引数を1つずつ適用することが可能になります。 これがカリー化の原理です(アメリカの論理Haskell B. Curryの名前による)。 そのような関数に数値を「与える」と、別の関数が得られます。 これは簡単な例で簡単に確認できます。

 successor :: Integer -> Integer successor = plus 1
      
      





この手法は、関数の部分適用と呼ばれます。



このプレリュードでは、カリーとアンカリーの特別な関数を定義し、関数をカリー化するフォームに導きます。

 curry :: ((a, b) -> c) -> a -> b -> c curry fxy = f (x, y) uncurry :: (a -> b -> c) -> ((a, b) -> c) uncurry fp = f (fst p) (snd p)
      
      





どんな関数を書かないか、引数は1つだけになります。 ただし、まれな例外を除き、カレー種が望ましいです。 カリー化関数は、括弧の数を減らすことに加えて、使用時に多くの利点をもたらします。 後続の講義でそれを確信します。 そしてそれが今日のすべてです。

テキストを書くとき、私はセルゲイ・ミハイロヴィチ・アブラモフによる講義の要約に頼っていました。

ご清聴ありがとうございました!



All Articles