繁体   English   中英

类型级别集的传递“子集”类

[英]Transitive 'Subset` class for type-level-sets

我正在使用 Dominic Orchard 的类型级别集库,它非常接近他的论文

我正在构建一个 DSL,用于在同步并发程序期间表达各方之间的通信。 我需要的一件事是能够表达涉及原始社区子集的“子程序”; 这将与fromUniversal结合使用。

这是我的代码的精简版:

module Lib () where

import Data.Type.Nat (Nat)
import Data.Type.Set (IsSet, Subset)
import Polysemy (Sem, makeSem, reinterpret)

data Located (parties :: [Nat]) v = Located v

data Com (parties :: [Nat]) m a where
  SendInt :: forall recipients senders parties m.
             (Subset recipients parties,
              Subset senders parties) =>
             Located senders Int -> Com parties m (Located recipients Int)
  FromUniversal :: forall parties m a.
               Located parties a -> Com parties m a

-- Polysemy uses template haskell:
makeSem ''Com
--sendInt :: Member...=> (Located senders Int) -> Sem r (Located recipients Int)
--fromUniversal :: Member (Com parties) r => (Located parties a) -> Sem r a
--We can manually write them out instead of using makeSem;
--that helps make Located's type argument explicit.

-- Lift a program in a small community (clique) into a larger community's monad. 
runClique :: forall parties clq s r a.
          (IsSet parties,
           IsSet clq,
           Subset clq parties) =>
          Sem (Com clq ': r) a -> Sem (Com parties ': r) (Located clq a)
runClique program = do
    a <- (reinterpret _clique) program
    return (Located a)
  where _clique :: forall rInitial x.
                   Com clq (Sem rInitial) x -> Sem (Com parties ': r) x
        _clique (SendInt l) = sendInt l

_clique ,有提供Subset recipients clqSubset csl parties上下文; 我需要 GHC 以某种方式理解这意味着Subset recipients parties 但是没有这样的实例可用。

为了类型级集的目的,我如何表示“子集”的传递性?

这是错误消息:

~/.../src/Lib.hs:35:31: error:
    • Could not deduce (Subset recipients parties)
        arising from a use of ‘sendInt’
      from the context: (IsSet parties, IsSet clq, Subset clq parties)
        bound by the type signature for:
                   runClique :: forall k (parties :: [Nat]) (clq :: [Nat]) (s :: k)
                                       (r :: [(* -> *) -> * -> *]) a.
                                (IsSet parties, IsSet clq, Subset clq parties) =>
                                Sem (Com clq : r) a -> Sem (Com parties : r) (Located clq a)
        at src/Lib.hs:(25,1)-(29,72)
      or from: (x ~ Located recipients Int, Subset recipients clq,
                Subset senders clq)
        bound by a pattern with constructor:
                   SendInt :: forall k (recipients :: [Nat]) (senders :: [Nat])
                                     (parties :: [Nat]) (m :: k).
                              (Subset recipients parties, Subset senders parties) =>
                              Located senders Int -> Com parties m (Located recipients Int),
                 in an equation for ‘_clique’
        at src/Lib.hs:35:18-26
    • In the expression: sendInt l
      In an equation for ‘_clique’: _clique (SendInt l) = sendInt l
      In an equation for ‘runClique’:
          runClique program
            = do a <- (reinterpret _clique) program
                 return (Located a)
            where
                _clique ::
                  forall rInitial x.
                  Com clq (Sem rInitial) x -> Sem (Com parties : r) x
                _clique (SendInt l) = sendInt l
   |
35 |         _clique (SendInt l) = sendInt l
   |                               ^^^^^^^^^

我试着简单地添加

instance {-# OVERLAPS #-} (Subset s t, Subset t v) => Subset s v where
  subset xs = subset (subset xs :: Set t)

到 Lib.hs(显然Subset不是封闭世界;我认为); 这会给出各种不同的错误消息,具体取决于我使用的编译器选项,或者我是否将OVERLAPS INCOHERENT 其要点似乎是 GHC 无法选择要使用的实例,即使我保证它会没事。

我尝试在_clique明确recipient类型(因此我可以将所需的Subset recipients parties添加到上下文中),但似乎无论我做什么reinterpret总是引入/需要“新鲜” x和/或recipients 我还没有找到为实际使用的类型变量提供上下文的方法。

这似乎不太可能是不可能的,但我已经坚持了一天,而且我已经超出了我的深度。

编辑

我一直在使用以下解决方案进行该项目; 它显然是平庸的。 具体来说,除了传递性之外,还有很多属性是很好的,比如两个集合都是第三个集合的子集,那么它们的并集也是第三个集合的子集。 对 Haskell 的类型系统来说,“免费”获得这样的属性可能太过分了……

到目前为止,我能想出的最佳解决方案是Ghosts of Departed Proofs ,我可以用它来将子集的逻辑移出类型系统。 它有点笨重,我完全不确定我是否正确使用它。

子集.hs

module Subset (
  immediateSubset,
  Subset,
  SubsetProof,
  transitiveSubset,
  unionOfSubsets
) where

import Data.Type.Set (Subset, Union)
import Logic.Classes (Transitive, transitive)
import Logic.Proof (axiom, Proof, sorry)

data Subset' s t where {}
instance Transitive Subset' where {}
type SubsetProof s t = Proof (Subset' s t)

immediateSubset :: (Subset s t) =>
                   SubsetProof s t
immediateSubset = axiom
transitiveSubset :: forall k (s :: [k]) (t :: [k]) (v :: [k]).
                    SubsetProof s t -> SubsetProof t v -> SubsetProof s v
transitiveSubset = transitive
unionOfSubsets :: forall k (s1 :: [k]) (s2 :: [k]) (t :: [k]).
                  SubsetProof s1 t -> SubsetProof s2 t -> SubsetProof (Union s1 s2) t
unionOfSubsets s1t s2t = sorry

库文件

module Lib {-()-} where

import Data.Type.Nat (Nat)
import Data.Type.Set (IsSet)
import Polysemy (Sem, makeSem, reinterpret)

import Subset (immediateSubset, Subset, SubsetProof, transitiveSubset)


data Located (parties :: [Nat]) v = Located v

data Com (parties :: [Nat]) m a where
  SendInt :: forall recipients senders parties m.
             SubsetProof recipients parties 
             -> SubsetProof senders parties
             -> Located senders Int
             -> Com parties m (Located recipients Int)
  FromUniversal :: forall parties m a.
                   Located parties a -> Com parties m a

-- Polysemy uses template haskell:
makeSem ''Com
--sendInt :: Member (Com parties) r => (Located senders Int) -> Sem r (Located recipients Int)
--fromUniversal :: Member (Com parties) r => (Located parties a) -> Sem r a
--we can manually write out the functions instead of useing makeSem;
--that might help make Located's type artument explicit, but I don't think it matters here.

-- "lift" a program in a small community (clique) into a larger community's monad. 
runClique :: forall parties clq r a.
          (IsSet parties,
           IsSet clq,
           Subset clq parties) =>
          Sem (Com clq ': r) a
          -> Sem (Com parties ': r) (Located clq a)
runClique = (Located <$>) . (reinterpret _clique)
  where cp = immediateSubset :: SubsetProof clq parties
        _clique :: forall rInitial x.
                   Com clq (Sem rInitial) x -> Sem (Com parties ': r) x
        _clique (SendInt rc sc x) = sendInt (transitiveSubset rc cp) (transitiveSubset sc cp) x
        _clique (FromUniversal (Located v)) = return v

GHC Haskell 只真正支持两种类型的约束的传递性:

  1. (名义)等式约束

    (a ~ b, b ~ c) => a ~ c
  2. 表征等式约束

    (Coercible ab, Coercible bc) => Coercible ac

这些规则(非常小心地)被融入到完全神奇的~Coercible约束的约束求解过程中; 约束语言中没有其他传递性。 基本问题是,如果你有一个类

class C a b

你写

instance (C a b, C b c) => C a c

那么b是不明确的。 当 GHC 试图求解C ac ,它不知道你想要什么b 目前还没有任何方式让用户指示在需要约束的地方使用哪个b ,因此该实例确实无法使用。

Data.Type.Set中的Subset类型看起来不像一个相等或Coercible约束,所以你不能这样做。

是否有其他方法可以表达列表是 GHC可以识别为可传递的另一个列表的子集的想法? 我不知道。 假设我们有类似的东西

class Subset' a b
transitive :: (Subset' a b, Subset' b c) => SomeProof a b -> SomeProof b c -> Dict (Subset' a c)

如果可以在不使用证明参数的情况下定义transitive我会感到惊讶。 此外,实际使用这样的Subset'可能很困难,甚至不可能。

Subset'约束可能看起来像以下之一:

type Subset' a b = Union a b ~ Nub (Sort b)
type Subset' a b = Intersection a b ~ Nub (Sort a)

您可能会也可能不会使用所提供的UnionSortNub ,并且您必须想出自己的Intersection 我毫不怀疑任何这样的项目都会很复杂。 您必须使用所提供的证据结构来构建必要的相等性。 然后毕竟......你真正得到了什么? 这看起来像是一个死胡同。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM