Каков рекомендуемый способ обработки сложно составленного модуля (plain-old-data в OO) в Haskell?
Вопрос
Я новичок в Haskell.
В статически типизированных OO-языках (например, Java) все сложные структуры данных представлены в виде классов и экземпляров.Объект может иметь множество атрибутов (полей).И другим объектом может быть значение поля.К этим полям можно получить доступ по их именам и статически ввести по классу.Наконец, эти объекты строят огромный граф объектов, которые связаны друг с другом.Большинство программ использует график данных, подобный этому.
Как я могу заархивировать эти функции в Haskell?
Решение
HASKELL имеет алгебраические типы данных, которые могут описать структуры или союзы структур, так что что-то данного типа может иметь одно из нескольких различных наборов полей.Эти поля могут быть установлены и доступны как к позиционному или по именам с помощью синтаксиса записи.
См. Здесь: http://learnyouahaskell.com/makey-тип-и-типографы
Другие советы
Если у вас действительно есть данные без поведения, это прекрасно соотносится с записью на Haskell:
data Person = Person { name :: String
, address :: String }
deriving (Eq, Read, Show)
data Department = Management | Accounting | IT | Programming
deriving (Eq, Read, Show)
data Employee = Employee { identity :: Person
, idNumber :: Int
, department :: Department }
| Contractor { identity :: Person
, company :: String }
deriving (Eq, Read, Show)
Это говорит о том, что Person
это Person
у кого есть name
и address
(оба String
ы);a Department
является либо Management
, Accounting
, IT
, или Programming
;и ан Employee
является либо Employee
у кого есть identity
(а Person
), ан idNumber
(ан Int
), и a department
(а Department
), или является Contractor
у кого есть identity
(а Person
) и a company
(а String
).То deriving (Eq, Read, Show)
строки позволяют вам сравнивать эти объекты на предмет равенства, считывать их и преобразовывать в строки.
В общем, тип данных Haskell представляет собой комбинацию объединений (также называемых суммы) и кортежи (также называемые продукты).1 То |
s обозначает выбор (союз):один Employee
является любой один Employee
или в Contractor
, а Department
это одна из четырех вещей и т.д.В общем случае кортежи записываются примерно следующим образом:
data Process = Process String Int
Это говорит о том, что Process
(в дополнение к имени типа) - это конструктор данных в день тип настройки? String -> Int -> Process
.Таким образом, например, Process "init" 1
, или Process "ls" 57300
.A Process
должен иметь оба a String
и ан Int
существовать.Обозначение записи, используемое выше, является просто синтаксическим сахаром для этих продуктов;Я также мог бы написать data Person = Person String String
, а затем определяется
name :: Person -> String
name (Person n _) = n
address :: Person -> String
address (Person _ a) = a
Однако нотация записей может быть полезна для сложных структур данных.
Также обратите внимание, что вы можете параметризовать тип Haskell по сравнению с другими типами;например, трехмерной точкой может быть data Point3 a = Point3 a a a
.Это означает, что Point3 :: a -> a -> a -> Point3 a
, чтобы можно было написать Point3 (3 :: Int) (4 :: Int) (5 :: Int)
чтобы получить Point3 Int
, или Point3 (1.1 :: Double) (2.2 :: Double) (3.3 :: Double)
чтобы получить Point3 Double
.(или Point3 1 2 3
чтобы получить Num a => Point3 a
, если вы видели классы типов и перегруженные числовые литералы.)
Это то, что вам нужно для представления графика данных.Однако примите к сведению:одна из проблем для людей, переходящих с императивных языков на функциональные — или, на самом деле, между любыми двумя разными парадигмами (C на Python, Prolog на Ruby, Erlang на Java, что угодно) — заключается в том, чтобы продолжать пытаться решать проблемы старым способом.Решение, которое вы пытаетесь смоделировать мочь не может быть сконструирован способом, поддающимся простым методам функционального программирования, даже если проблема заключается в этом.Например, в Haskell очень важно думать о типах, в отличие, скажем, от Java.В то же время реализация поведения для этих типов выполняется совершенно по-разному:функции более высокого порядка захватывают некоторые абстракции, которые вы видели в Java, но также и некоторые, которые нелегко выразить(map :: (a -> b) -> [a] -> [b]
, filter :: (a -> Bool) -> [a] -> [a]
, и foldr :: (a -> b -> b) -> b -> [a] -> b
приходит на ум).Так что оставляйте свои варианты открытыми и подумайте о том, чтобы решать свои проблемы функциональным способом.Конечно, может быть, в этом случае вы и действуете на полную катушку.Но имейте это в виду, когда будете изучать новый язык.И получайте удовольствие :-)
1: И рекурсия:вы можете представить бинарное дерево, например, с помощью data Tree a = Leaf a | Branch a (Tree a) (Tree a)
.