[英]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 clq
和Subset 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 ,我可以用它来将子集的逻辑移出类型系统。 它有点笨重,我完全不确定我是否正确使用它。
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 只真正支持两种类型的约束的传递性:
(名义)等式约束
(a ~ b, b ~ c) => a ~ c
表征等式约束
(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)
您可能会也可能不会使用所提供的Union
、 Sort
和Nub
,并且您必须想出自己的Intersection
。 我毫不怀疑任何这样的项目都会很复杂。 您必须使用所提供的证据结构来构建必要的相等性。 然后毕竟......你真正得到了什么? 这看起来像是一个死胡同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.