Я пытаюсь смоделировать «атомы и списки» kdb / q через систему типов Haskell.
В kdb / q все данные построены из атомов. Атом - это несократимое значение определенного типа данных. Int, boolean и char - примеры атомов. Списки - это упорядоченные коллекции, построенные из атомов. Поскольку q - векторный язык, большинство встроенных операций атомарны, и поэтому он рекурсивно повторяется в структуре аргументов, пока не дойдет до атомов.
Например:
(1; 2; 3) - простой список целых чисел 1, 2, 3
(1.0; 2; (3; 4; 5)) - это общий список из 1.0 (float), 2 (int) и простой список int (3; 4; 5)
neg - это функция, которая отменяет одно число. Например:
neg 1 дает -1
neg -1.0 дает 1f
neg (1.0; 2; (3; 4; 5)) дает (-1f; -2; (- 3; -4; -5)).
Это то, что вдохновило меня на попытку смоделировать такое поведение в типах Haskell. Тип данных должен состоять из типа атома и списка.
Ниже приводится упрощенная версия того, что у меня есть. И я также пошел дальше, чтобы попытаться сделать его экземпляром Foldable и Traversable.
data Atom = I Int
| C Char
| D Double
deriving Show
data Q a = QAtom a
| QList [Q a]
deriving Show
instance Functor Q where
fmap f (QAtom a) = QAtom (f a)
fmap f (QList qs) = QList $ fmap (fmap f) qs
instance Foldable Q where
foldMap f (QAtom a) = f a
foldMap f (QList qs) = mconcat $ fmap (foldMap f) qs
instance Traversable Q where
sequenceA (QAtom fa) = fmap QAtom fa
sequenceA (QList []) = pure $ QList []
sequenceA (QList (qfa:qfas)) = concatL <$> (sequenceA qfa) <*> (sequenceA (QList qfas))
where
concatL (QAtom a) (QList qas) = QList ((QAtom a):qas)
Это то, что у меня есть, и оно компилируется, но мне не особенно нравится функция concatL, которая не охватывает все шаблоны в соответствии с типом. Когда я начинаю добавлять новый конструктор значений QDict [(Q Atom, Q a)] в Q, это становится еще хуже.
Правильно ли я смоделировал исходные данные? Стоит ли мне вообще попытаться сделать его проходимым? Однако я думал, что Traversable необходим, если мне нужно использовать тип данных с Maybe или Either для моделирования ошибок.
Любой совет приветствуется.
РЕДАКТИРОВАТЬ: отредактированное форматирование кода q
Q
без переменной типа, какdata Q = QAtom Atom | QList [Q]
. Это позволяет вам создавать списки типаQList [QAtom (D 1.0), QAtom (I 2), QList [QAtom (I 3), QAtom (I 4), QAtom (I 5)]]
, как в вашем примере с Q; вы не можете представить такую структуру своим текущим типом. Но кроме этого я не знаю; Мне нужно еще немного изучить ваш код и посмотреть, не найду ли я что-нибудь еще, чтобы дать совет. РЕДАКТИРОВАТЬ: Я был неправ, см. следующий комментарий - person bradrn   schedule 11.02.2020QAtom a
какQAtom (Atom a)
. Ваше текущее определениеQ
действительно хорошо! Извините за путаницу. - person bradrn   schedule 11.02.2020Traversable
: я думаю, вам обязательно стоит сделать его экземпляромFoldable
и т. Д., Но, как вы уже заметили, ваш экземплярTraversable
немного забавен. Лучший способ реализовать этот случай - избежать сопоставления с образцом и вместо этого использовать экземплярTraversable []
:sequenceA (QList fl) = fmap QList $ sequenceA $ fmap sequenceA fl
. (Вы можете представить себе это как упорядочивание каждого отдельного элементаQList
, а затем упорядочение всего списка действий, который дает вам.) Но я считаю, что гораздо проще реализоватьtraverse
, чемsequenceA
. - person bradrn   schedule 11.02.2020