我正在尝试通过Haskell类型系统为kdb / q“原子和列表”建模。
在kdb / q中,所有数据都是从原子构建的。原子是特定数据类型的不可约值。 Int,布尔值和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
并且取负(1.0; 2;(3; 4; 5))得出(-1f; -2;(-3; -4; -5))。
这就是促使我尝试在Haskell类型中对此行为进行建模的原因。数据类型应包含原子类型和列表。
以下是我到目前为止的简化版本。而且我还进一步尝试使其成为可折叠和可遍历的实例。
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函数,该函数不能根据类型覆盖所有模式。一旦我开始向Q添加新的值构造函数QDict [(Q Atom,Q a)],情况就会变得更糟。
我是否正确建模了原始数据?我是否应该尝试使其可穿越?但是,我认为,如果需要将数据类型与Maybe或Either结合使用以对错误进行建模,则Traversable是必需的。
任何建议都值得赞赏。
我正在尝试通过Haskell类型系统为kdb / q“原子和列表”建模。在kdb / q中,所有数据都是从原子构建的。原子是特定数据类型的不可约值。 Int,boolean和char ...
任何类型最多具有一个Traversable
实例,并且编译器知道如何为您派生它。如果先执行:set -ddump-deriv -dsuppress-all -XDeriveTraversable -XStandaloneDeriving
,然后执行deriving instance Traversable Q
,则可以看到“正确”的答案。如果您掌握了这些知识并将其应用于您的实例,您将获得以下信息: