我正在使用 Dominic Orchard 的type-level-sets库,该库非常接近他的论文。
我正在构建一个 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)
to Lib.hs (apparently Subset
isn't closed-world; I think); this gives a variety of different error messages depending what compiler options I use, or if I swap out OVERLAPS
for INCOHERENT
. The jist of it seems to be that GHC can't pick an instance to use, even if I promise it'll be ok.
I tried making the recipient
type explicit in _clique
(so I can just add the needed Subset recipients parties
to the context), but it seems like no matter what I do reinterpret
always introduces/requires a "fresh" x
and/or recipients
; I haven't found a way of providing the context for the type-variable that's actually used.
It seems unlikely that this is impossible, but I've been stuck on it for a day and I'm out of my depth.
Edit
我一直在使用以下解决方案进行该项目;这显然是平庸的。具体来说,除了传递性之外,还有很多属性很好,比如两个集合都是第三个集合的子集,那么它们的并集也是第三个集合的子集。对于 Haskell 的类型系统来说,“免费”获得这样的属性可能太过分了……