Проблема с пониманием уравнения, используемого для определения моноида на натуральных числах - PullRequest
1 голос
/ 11 июля 2020

Рассмотрим следующий код:

import Data.Semigroup
newtype Sum a = Sum { getSum :: a } deriving (Eq, Ord, Show)

instance Num a => Semigroup (Sum a) where
Sum a <> Sum b = Sum (a + b)

instance Num a => Monoid (Sum a) where
mempty = Sum 0
mappend = (<>)

Я действительно не понимаю, что означает строка newtype Sum a = Sum { getSum :: a }. Определяется новый тип, polymorphi c on a. getSum :: Sum a -> a возвращает что-то типа a, которое, следовательно, может сочетаться с Sum. Но зачем нам здесь getSum и что делают { и }?

В чем смысл использования синтаксиса записи в этом случае?

1 Ответ

0 голосов
/ 11 июля 2020

Прежде всего, {} указывает синтаксис записи. Считайте, что это представляет человека с именем и возрастом:

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

Оба эквивалентны, но первый короче, поэтому он используется чаще.

...