サーチ…


基本的な構文

レコードは、フィールドに名前を付けることができるような和代数data型の拡張です。

data StandardType = StandardType String Int Bool --standard way to create a sum type

data RecordType = RecordType { -- the same sum type with record syntax
    aString :: String
  , aNumber :: Int
  , isTrue  :: Bool
  }

フィールド名を使用して、名前付きフィールドをレコードから取得することができます

> let r = RecordType {aString = "Foobar", aNumber= 42, isTrue = True}
> :t r
  r :: RecordType
> :t aString
  aString :: RecordType -> String
> aString r
  "Foobar"

レコードはパターンマッチングすることができます

case r of
  RecordType{aNumber = x, aString=str} -> ... -- x = 42, str = "Foobar"

すべてのフィールドに名前を付ける必要はないことに注意してください

レコードはフィールドの名前を付けて作成されますが、通常の合計タイプとして作成することもできます(フィールドの数が少なく、変更されにくい場合に便利です)

r  = RecordType {aString = "Foobar", aNumber= 42, isTrue = True}
r' = RecordType  "Foobar" 42 True

レコードが名前付きフィールドなしで作成された場合、コンパイラは警告を発行し、結果の値はundefinedなります。

> let r = RecordType {aString = "Foobar", aNumber= 42}
  <interactive>:1:9: Warning:
     Fields of RecordType not initialized: isTrue
> isTrue r
  Error 'undefined'

レコードのフィールドは、その値を設定することによって更新できます。記載されていないフィールドは変更されません。

> let r = RecordType {aString = "Foobar", aNumber= 42, isTrue = True}
> let r' = r{aNumber=117}
    -- r'{aString = "Foobar", aNumber= 117, isTrue = True}

複雑なレコードタイプのレンズを作成することはしばしば役に立ちます。

フィールド値の変更中にレコードをコピーする

このタイプがあるとします:

data Person = Person { name :: String, age:: Int } deriving (Show, Eq)

2つの値:

alex = Person { name = "Alex", age = 21 }
jenny = Person { name = "Jenny", age = 36 }

alexからコピーして変更する値を指定することで、 Person型の新しい値を作成できます。

anotherAlex = alex { age = 31 }

alexanotherAlexの値はanotherAlexようになります。

Person {name = "Alex", age = 21}

Person {name = "Alex", age = 31}

新しいタイプのレコード

newtypeではレコード構文を使用できますが、正確に1つのフィールドを持つコンストラクタが1つだけ存在するという制限があります。ここでの利点は、newtypeをラップ解除する関数の自動作成です。これらのフィールドは、モナドの場合はrun 、モノイドの場合はget 、その他のタイプの場合はunで始まることがよくあります。

newtype State s a = State { runState :: s -> (s, a) }

newtype Product a = Product { getProduct :: a }

newtype Fancy = Fancy { unfancy :: String } 
  -- a fancy string that wants to avoid concatenation with ordinary strings

レコード構文は通常、値を形成するために使用されることはなく、フィールド名はアンラッピングに厳密に使用されることに注意することが重要です

getProduct $ mconcat [Product 7, Product 9, Product 12]
-- > 756

RecordWildCards

{-# LANGUAGE RecordWildCards #-}

data Client = Client { firstName     :: String
                     , lastName      :: String
                     , clientID      :: String 
                     } deriving (Show)

printClientName :: Client -> IO ()
printClientName Client{..} = do
    putStrLn firstName
    putStrLn lastName
    putStrLn clientID

Client{..}パターンは、コンストラクタのClientすべてのフィールドをスコープ内に持ち込み、パターンと同じです

Client{ firstName = firstName, lastName = lastName, clientID = clientID }

また、他のフィールドマッチャーと組み合わせることもできます:

Client { firstName = "Joe", .. }

これは

Client{ firstName = "Joe", lastName = lastName, clientID = clientID }

フィールドラベルを使用したデータ型の定義

フィールドラベルを使用してデータ型を定義することは可能です。

data Person = Person { age :: Int, name :: String }

この定義は、データ型の一部にアクセスするために使用できるレコードアクセサも定義しているため、通常のレコード定義とは異なります。

この例では、2つのレコードアクセサは、規定されているagename私たちがアクセスすることを可能にする、 agenameをそれぞれのフィールドを。

age :: Person -> Int
name :: Person -> String

レコードアクセサは、コンパイラによって自動的に生成されるHaskell関数です。したがって、それらは通常のHaskell関数のように使用されます。

フィールドに名前を付けることによって、コードを読みやすくするために、フィールドラベルを他のコンテキストで使用することもできます。

パターンマッチング

lowerCaseName :: Person -> String
lowerCaseName (Person { name = x }) = map toLower x

パターンマッチング中の関連フィールドラベルの位置にある値を、定義のRHSで使用できる新しい値(この場合はx )にバインドすることができます。

NamedFieldPunsとのパターンマッチング

lowerCaseName :: Person -> String
lowerCaseName (Person { name }) = map toLower name

代わりに、 NamedFieldPuns拡張では、照合したいフィールドラベルを指定するだけで、この名前は定義のRHSでシャドーされるので、 nameはレコードアクセサではなく値を参照します。

RecordWildcardsパターンマッチング

lowerCaseName :: Person -> String
lowerCaseName (Person { .. }) = map toLower name

RecordWildCardsを使用して一致さRecordWildCards 、すべてのフィールドラベルがスコープに入れられます。 (この特定の例では、 nameage

この拡張は、 Personの定義が不明な場合に値がどのようにスコープに入れられるかが明確でないため、少し議論の余地があります。

更新を記録する

setName :: String -> Person -> Person
setName newName person = person { name = newName }

フィールド・ラベルを使用してデータ型を更新するための特別な構文もあります。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow