我无法理解类型应用程序的工作方式。当sing
中对refuteRefuteKnockable
的调用在没有类型应用程序的情况下无法进行类型检查时,为何sing
中的knockableOrOpened
无法在没有类型应用程序的情况下使用?
refuteRefuteKnockable :: SingI s => Refuted (Refuted (Knockable s)) -> Knockable s
refuteRefuteKnockable rrK =
case isKnockable $ sing of
Proved k -> k
Disproved rK -> absurd $ rrK rK
knockableOrOpened :: forall s. SingI s => Or Knockable ((:~:) Opened) s
knockableOrOpened =
case sing @s of
SOpened -> OrRight $ Refl
SClosed -> OrLeft KnockClosed
SLocked -> OrLeft KnockLocked
我正在使用以下代码库:https://github.com/mstksg/inCode/blob/master/code-samples/singletons/Door3.hs
答案 0 :(得分:7)
类型推断是原因。此类型包含./build/sbt package
...
s
所以
refuteRefuteKnockable :: SingI s => Refuted (Refuted (Knockable s)) -> Knockable s
^^^^^^^^^^^
必须具有类型 refuteRefuteKnockable rrK =
case isKnockable $ sing of
Proved k -> k
^^^
。因此,推断出Knockable s
的类型,可能也包含Proved k
。这与s
的类型相同,从中我们推断应该对isKnockable $ sing
应用哪种类型(利用sing
的签名)。 GHC为我们完成了所有这一切。
在后一个示例中,我们无法执行相同的推理。
isKnockable
是模棱两可的,因为即使三个分支必须返回已知类型,我们仍然可以使用与case sing of
SOpened -> OrRight $ Refl
SClosed -> OrLeft KnockClosed
SLocked -> OrLeft KnockLocked
不同的类型调用sing
并进行所有类型检查。由于没有唯一 s
,因此推断无法正常工作。
请注意,上面我不得不猜测一些事情。如果您共享类型的定义,我们可能会更准确。 (即,s
定义在哪里?SOpened
等如何?)