講義ノート「最初のプログラミング言語としての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つだけになります。 ただし、まれな例外を除き、カレー種が望ましいです。 カリー化関数は、括弧の数を減らすことに加えて、使用時に多くの利点をもたらします。 後続の講義でそれを確信します。 そしてそれが今日のすべてです。
テキストを書くとき、私はセルゲイ・ミハイロヴィチ・アブラモフによる講義の要約に頼っていました。
ご清聴ありがとうございました!

Source: https://habr.com/ru/post/J204566/


All Articles