今日、約束したとおり、ユーザーデータタイプ、関数定義、パターンマッチングについて簡単に説明します。
前の記事:
基本次の記事:
型クラス、モナドまえがき
ファイルの拡張子は.hsまたは.lhsです(Literate Haskellの場合は、コメントとコードを逆の方法で記述します)。
これらをインタープリターにロードするには、ghci file.hsと呼ぶか、コマンドcdおよび:lを使用します。
gchi> :cd c:/some/haskell
ghci> :l file.hs
[1 of 1] Compiling Main ( file.hs, interpreted )
Ok, modules loaded: Main.
ghci>
確かに、変更が行われたときに自動的にリロードを行う便利なIDEがありますが、バックライトエディターを使用しています。
データ型
データ型は、データキーワード、型名を使用して決定され、次に|を介してコンストラクターをリストします。
データ型とコンストラクターは大文字で始まり、関数名は小さい名前で始まる必要があります。
data Color = Red | Green | Blue
コンストラクターにはパラメーターを含めることができます。
import Data . Word ( Word8 ) -- Word8 Data.Word
data Color = Red | Green | Blue | Custom Word8 Word8 Word8
さらに、使用されるタイプによってタイプ自体をパラメーター化できます。 リストの例:
data List a = Null | Cons a ( List a )
つまり 要素aのリストは空であるか、(head)aおよび(tail)List aで構成されています
デザイナーの説明では、次の砂糖を使用できます。
data List a = Null | Cons { listHead :: a , listTail :: List a }
2つの関数を自動的に決定します
listHead :: List a -> a
listTail :: List a -> List a
基本的に実装されています
関数定義と照合パターン(パターン照合)
リストの上に便利な関数を定義します。
length Null = 0
length ( Cons _ xs ) = 1 + length xs
ここでは、パターンマッチングを使用しました。 関数パラメーターは、サンプル(
Null
および
Cons _ xs
)と比較され(決定の順序が重要)、適切なオプションが選択されます。
_
は任意の値を意味しますが、重要ではありません。 つまり
Cons _ xs
は、空でないリストに対して渡されます。
サンプルは任意に複雑にすることができます。
someFunc ( Cons 5 ( Cons _ ( Cons 3 ( Cons _ Null ) ) ) ) = True
someFunc _ = False
ただし、コンストラクター(および埋め込みリテラル)のみを使用できます。 つまり この例では:
x = 4
wrong x = True
wrong _ = False
xは4として定義されている値ではなく、自由な名前であるため、最初のオプションは常に機能します。
部品サンプルの「逆アセンブル」と同時に関数パラメーター自体が必要な場合(突然必要な場合にすべてを収集しないように)、次のように記述できます。
someFunc v @ ( Cons 5 ( Cons _ ( Cons 3 ( Cons _ Null ) ) ) ) = -- v - ,
パターンマッチングは関数内でも使用できます。 最も一般的なケースは次のとおりです(例の無意味さについては申し訳ありませんが、そのような一般的なケースが実際の例と重なったのは覚えていません。構文を表示する必要があります)。
someFunc2 n = case n of
Null -> "Null"
Cons _ Null -> "One"
Cons _ ( Cons x _ )
| x == 0 -> "0"
| x == 1 -> "1"
| otherwise -> "otherwise" -- otherwise True
上記の例の最後の3行は、いわゆるパターンガードです。 値が最後のパターンに該当する場合(この場合、最後のパターンである必要はなく、各パターンにパターンガードを書き込むことができます)、
True
が与えるものが選択されます。 同じメカニズムが機能に対して機能します:
someFunc3 ( x : xs )
| isSomePredicate x = xs
| x == 0 = []
| otherwise = ( x : xs )
さらに、追加の非標準的な機会があります。
Bool
型の式を記述する代わりに、サンプルを記述し、それに一致する式をチェックできます。次に例を示します。
someFunc4 ( x : xs )
| ( 2 : ys ) <- filter even xs = ys -- 2
| ( 4 : y : [] ) <- xs = [ y ] -- xs 2- , - 4
| otherwise = ( x : xs )
サンプルがすべての可能な値をカバーする方法ではなく、そこに表示される場合、例外が発生します。
特に、listHead(および標準ヘッドも)は空のリストを処理できません。
ghci> listHead Null
*** Exception: No match in record selector Main.listHead
ghci> head []
*** Exception: Prelude.head: empty list
2番目のオプションは、実際には空のリストのヘッドが定義されているため、より多くの情報を提供しますが、例外をスローします。 このような場合、標準エラー関数を使用できます
listHead Null = error "listHead: empty list"
listHead ( Cons x _ ) = x
ghci> listHead Null
*** Exception: listHead: empty list
対応する標準と同様に、リストの標準関数の一部を定義します
listMap f Null = Null
listMap f ( Cons x xs ) = Cons ( fx ) ( listMap f xs )
listFilter p Null = Null
listFilter p ( Cons x xs )
| px = Cons x ( listFilter p xs )
| otherwise = listFilter p xs
listFoldr fv Null = v
listFoldr fv ( Cons x xs ) = fx $ listFoldr fv xs
( $ )
アプリケーション演算子であり、関数と引数を取ります。 その本質は、余分なブラケットを置く必要がないことです。 の代わりに
foo ( bar 3 ( baz 56 "x" ) )
書ける
foo $ bar 3 $ baz 56 "x"
演算子は関数と同じ方法で定義されますが、プレフィックス形式で使用する場合は、括弧で囲む必要があります。
この例では、エントリは正しいです:
Null @++ right = right
( @++ ) left Null = left
( Cons l ls ) @++ right = Cons l ( ls @++ right )
さらに、演算子に優先度と左または右の結合性を割り当てることができます。 キーワード
infixl
および
infixr
それぞれ使用します。
オペレーターの優先順位を調べるには、インタープリターで次のコマンドを使用できます。
ghci> :i (++)
(++) :: [a] -> [a] -> [a] -- Defined in GHC.Base
infixr 5 ++
5は1から9までの優先順位です。それが高いほど、優先順位は高くなります
演算子は似ている
( ++ )
ので、同じ優先順位を与えます
infixr 5 @++
関数はインフォグラフィックで呼び出すことができることを思い出してください;このため、その名前は引用符で囲まれています。 実際、このように定義することもできます。 以下は、関数の完全に正当な定義です。
lst `atIndex` n = lst !! n
便宜上補助機能を定義します
toList Null = []
toList ( Cons x xs ) = x : ( toList xs )
fromList [] = Null
fromList ( x : xs ) = Cons x ( fromList xs )
最後に、通常のリストと同じ方法でリストを文字列に変換する関数を作成します。 これを行うには、最初にリスト項目の間に追加要素を挿入する関数を作成します。 from
[ 1 , 2 , 3 ]
は
[ 1 , 5 , 2 , 5 , 3 ]
1、5、2、5、3
[ 1 , 2 , 3 ]
作成し
[ 1 , 5 , 2 , 5 , 3 ]
(挿入された要素が5の場合)
(何らかの理由で<font> 0 </ font>はvoidになります、ここでは( 0 )、それは落ちました5変更:)) :
listIntersperse with Null = Null
listIntersperse with ( Cons x xs ) = Cons x $ listFoldr ( \ x -> Cons with . Cons x ) Null xs
ここでは、ラムダが畳み込み関数として使用されます。 Lambdaは、
\ arg1 arg2 argN -> expr
として記述された匿名関数です。 その中で、パターンマッチングも使用できますが、パターンマッチングは1つのみです。 いくつかのサンプルに対していくつかのオプションを記述しても機能しませんが、必要であれば、いつでも
case ... of
使用できます。
lambda
\ x -> Cons with . Cons x
詳しく見てみましょう
\ x -> Cons with . Cons x
\ x -> Cons with . Cons x
、特定の値を取得し、この要素をリストにフックし、次に
with
要素をフックする関数を返します。その結果、
Cons with ( Cons x ... )
リスト
Cons with ( Cons x ... )
を取得し
Cons with ( Cons x ... )
つまり 最初の要素を除く各要素の前には
with
要素があります。
これで、リストを文字列に変換する関数を簡単に定義できます。
listShow lst = "[" ++ ( listFoldr ( ++ ) "" $ listIntersperse "," $ listMap show lst ) ++ "]"
listMap show lst
すべてのリストアイテムを文字列に変換します
listInterpserse ","
要素間にコンマを挿入します
listFoldr ( ++ ) ""
すべての行を1つに結合し、端から角かっこを追加します。 私たちはチェックします:
ghci> show [ 1 , 2 , 3 ] == listShow ( fromList [ 1 , 2 , 3 ] )
True
次回は型クラスといくつかの標準クラスについてお話します。