0

可能的目标是为 Haskell 中新定义的数据类型创建一个新的 Semigroup 类型类实例(对于那些知道Will Kurt 的“Get programming with Haskell”一书的人,我可以参考第 428 页,即顶点项目的结尾5 与锻炼扩展)。

有一个新定义的数据类型:

data HINQ m a b = HINQ (m a -> m b) (m a) (m a -> m a)
                | HINQ_ (m a -> m b) (m a)

此数据类型指定类似 SQL 的查询,其中m定义上下文(Monad 或 Alternative),(m a -> m b)是目标类似于 SQL 函数的函数SELECT,即定义想要在数据库中看到的属性类型,(m a)是一个“表”,应用前面的函数(类似于 SQL 的table_name),最后(m a -> m a)过滤掉正在寻找的属性(类似于 SQL 的WHERE)。

我的目标是使这个数据类型成为一个半群(最后是一个 Monoid)的实例。值得一提的是,所有需要的 Semigroup 实例a都是b假设的。

instance (Semigroup a, Semigroup (m a), Semigroup b,...) => 
          Semigroup (HINQ m a b) where
  (<>) (HINQ func1 start1 test1)
       (HINQ func2 start2 test2) =

所以它的粗略想法(在背景上看得更清楚)是可以将数据库的几个不同查询组合成一个查询,但我想不出如何合并两个不同的功能同时输入(m a -> m b)一个合并两个表(m a)...第一个想法是将它们合并到列表中,但是类型签名发生了变化,我还没有找到解决这个问题的方法。

4

1 回答 1

2

我想你不想一个Semigroup组合所有查询对是没有意义的——只有其中一个的输出类型与另一个的输入类型合理匹配的查询!幸运的是,我们有一个概念对应于Semigroup(实际上是一个类型化的Monoid,但足够接近)的“类型化”变体:Category

另外,我认为将查询与您正在查询的表结合起来是一个设计错误。它们在概念上是独立的概念;实际上,在编写两个查询时,您仍然只有一张表,而不是两张。所以:

data HINQ m a b = HINQ (m a -> m b) (m a -> m a)

instance Category (HINQ m) where
    id = HINQ id id
    HINQ slct whr . HINQ slct' whr' = HINQ (slct . whr . slct') whr'

恒等律很清楚,但左右WHERE子句使用的不对称看起来有点可疑,所以我们应该仔细检查结合律:

(HINQ s0 w0 . HINQ s1 w1) . HINQ s2 w2
= HINQ (s0 . w0 . s1) w1 . HINQ s2 w2
= HINQ (s0 . w0 . s1 . w1 . s2) w2
= HINQ s0 w0 . HINQ (s1 . w1 . s2) w2
= HINQ s0 w0 . (HINQ s1 w1 . HINQ s2 w2)

看起来不错!

编辑

呃,嗯……也许x . id = x法律毕竟不是那么清楚。哎呀!这可能是不可修复的,除非您只考虑包含函数的组成的相等性,在这种情况下,为什么不直接将Category实例用于函数呢?当然,您的另一个选择是不要求遵守身份法。这有点不寻常,但我想这在很大程度上取决于您的用例是否合理。

如果您更明确地表示您的过滤,则组合可能会更容易,例如作为a -> Boola -> m Bool代替m a -> m a. 这使您有更多机会在您的(.)实现中组合这两个过滤器,而不是像上面的实例那样将其中一个过滤器滚动到选择操作中。

于 2021-09-15T19:14:19.463 回答