Прежде всего, {}
указывает синтаксис записи. Считайте, что это представляет человека с именем и возрастом:
newtype Person = Person String Int
getName :: Person -> String
getName (Person x _) = x
getAge :: Person -> Int
getAge (Person _ x) = x
Это работает нормально, но теперь подумайте, хотите ли вы добавить домашний адрес и номер социального страхования:
newtype Person = Person String Int String Int
getName :: Person -> String
getName (Person x _ _ _) = x
getAge :: Person -> Int
getAge (Person _ x _ _) = x
getAddress :: Person -> String
getAddress (Person _ _ x _) = x
getSsn :: Person -> Int
getSsn (Person _ _ _ x) = x
Это уже становится беспорядком. А что, если вы хотите установить значение? Вот где появляется синтаксис записи:
-- this is generally spaced out onto multiple lines
newtype Person = Person { getName :: String, getAge :: Int, getAddress :: String, getSsn :: Int }
Вы по-прежнему можете создать человека с помощью такой конструкции, как Person name age addr ssn
, но вы также можете создать человека с помощью такой конструкции, как Person {getAddress = "foo", getSsn = 123, getAge = 12, getName = "bar"}
. При использовании синтаксиса записи функции getName :: Person -> String
, getAge :: Person -> Int
, getAddress :: Person -> String
и getSsn :: Person -> Int
определяются автоматически. Это в основном автоматическое c развертывание. Это действительно удобно, так часто хакеллеры определяют свои данные с помощью синтаксиса записи, чтобы добавить автоматический c распаковщик или деконструктор:
newtype Sum a = Sum { getSum :: a }
x :: Sum Int
x = Sum 1
y :: Int
y = getSum x
-- the alternative without record syntax:
newtype Sum' a = Sum' a
getSum' :: Sum' a -> a
getSum' (Sum' x) = x
x' :: Sum' Int
x' = Sum' 1
y' :: Int
y' = getSum' x
Оба эквивалентны, но первый короче, поэтому он используется чаще.