Если у вас действительно есть данные без поведения, это хорошо сопоставляется с записью на 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
с);Department
является либо Management
, Accounting
, IT
, либо Programming
;и Employee
является либо Employee
, который имеет identity
(a Person
), idNumber
(Int
) и department
(a Department
), либо являетсяContractor
, у которого есть identity
(Person
) и company
(String
).Строки deriving (Eq, Read, Show)
позволяют сравнивать эти объекты на равенство, считывать их и преобразовывать в строки.
В общем случае тип данных Haskell представляет собой комбинацию объединений (также называемых суммы *)1031 *) и кортежи (также называемые products ). 1 |
s обозначает выбор (объединение): Employee
равно либо an Employee
или Contractor
, Department
- это одна из четырех вещей и т. Д. В общем случае кортежи пишутся примерно так:
data Process = Process String Int
Это говорит о том, что Process
(в дополнение кимя типа) является конструктором данных с типом String -> Int -> Process
.Так, например, Process "init" 1
или Process "ls" 57300
.Process
должен иметь и 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)
.