Sam*_*ire 10 haskell type-inference ghc type-level-computation
我想让 GHC 推断出超过 GADT 模式匹配的约束。例如,假设我有两个表达式,每个表达式都有一个推断约束:
f :: _ => a
g :: _ => a
Run Code Online (Sandbox Code Playgroud)
(在我的用例中,这些推断的约束可能很大,因此手动写出它们是不可行的。)
假设我想使用f或g取决于布尔条件。天真地,我可以按如下方式进行:
h1 :: _ => Bool -> a
h1 c = if c then f else g
Run Code Online (Sandbox Code Playgroud)
假设我将推断约束称为 forf ct_f和 for g ct_g,那么 GHC 将推断出约束( ct_f, ct_g )为h1。
问题是这是一个过于严格的类型:如果布尔值是TrueI don't need ct_g,反之如果是FalseI don't need ct_f。所以我尝试使用标准机制来启用这种依赖约束:
data SBool (c :: Bool) where
SFalse :: SBool False
STrue :: SBool True
h2 :: _ => SBool bool -> a
h2 = \case
STrue -> f
SFalse -> g
Run Code Online (Sandbox Code Playgroud)
但是这不起作用,因为 GHC 的部分类型签名算法拒绝浮动约束超过 GADT 模式匹配。相反,我可以尝试明确告诉 GHC 要做什么:
ifC :: forall ct_t ct_f bool x. SBool bool -> ( ct_t => x ) -> ( ct_f => x ) -> ( If bool ct_t ct_f => x )
ifC STrue a _ = a
ifC SFalse _ b = b
h3 :: _ => SBool bool -> a
h3 c = ifC c f g
Run Code Online (Sandbox Code Playgroud)
这种方法也失败了,这次是因为 GHC 认为类型签名ifC不明确,即 GHC 需要用户显式传递约束,如
h4 c = ifC @ct_f @ct_g c f g
Run Code Online (Sandbox Code Playgroud)
不幸的是,我无法明确地传递这些约束:我要求 GHC 推断它们,并且无法引用它们。例如,人们可能会尝试将它们纳入范围,如下所示:
h5 :: _ => SBool bool -> a
h5 c =
let
f :: _ct_f => a
f' = f
g :: _ct_g => a
g' = g
in
if_C @_ct_f @_ct_g c f' g'
Run Code Online (Sandbox Code Playgroud)
但这行不通,因为 GHC 不支持命名通配符来代替额外的约束(即使支持,它们的范围也不会正确)。
是否有另一种方法可以让 GHC 推断:
h :: ( If bool ct_f ct_g ) => a
Run Code Online (Sandbox Code Playgroud)
Aki*_*AKI -1
我用 改进了一些代码ImpredicativeTypes。
type family GetBool a where
GetBool (SBool True) = True
GetBool (SBool False) = False
data TF (a :: Constraint) x = TF x
class SIf a pt pf x where
ifC' :: a -> TF pt x -> TF pf x -> (If (GetBool a) pt pf => x)
instance ((t => x) ~ (f => x)) => SIf (SBool True) t f x where
ifC' _ (TF t) _ = t
instance ((t => x) ~ (f => x)) => SIf (SBool False) t f x where
ifC' _ _ (TF f) = f
h3' :: _ => SBool bool -> a
h3' c = ifC' c f g
Run Code Online (Sandbox Code Playgroud)
它可以用来Num a举例说明。
*Main> :t h3' 3
h3' 3
:: (If (GetBool (SBool bool)) pt pf, SIf (SBool bool) pt pf a,
Num (SBool bool)) =>
a
Run Code Online (Sandbox Code Playgroud)
let x = h3' f目前也可以使用,但并不完美。我想我们所做的是黑魔法......
| 归档时间: |
|
| 查看次数: |
136 次 |
| 最近记录: |