haskell - 从任意未知 Nats 中提取值

标签 haskell types type-constraints type-families type-level-computation

给定类型级列表函数(来自 this blog post)

type family Length (xs :: [*]) :: Nat where
    Length '[] = 0
    Length (_ ': xs) = 1 + Length xs
“硬编码”类型列表长度的值提取按预期工作
t1 :: Integer
t1 = natVal (Proxy :: Proxy (Length '[Int]))
t1 = 1 .但是,创建一个从任意列表中获取值的函数似乎失败了。
t2 :: forall (xs :: [*]). Proxy xs -> Integer
t2 _ = natVal (Proxy :: Proxy (Length xs))
给出错误
    • No instance for (KnownNat (Length xs))
        arising from a use of ‘natVal’
这似乎很不幸但合理,因为只有文字是“已知的”。但是,强制满足如下约束会导致对模棱两可的类型的提示。
unsafeKnownConstr :: c :~: (KnownNat n :: Constraint)
unsafeKnownConstr = unsafeCoerce Refl

t3 :: forall (xs :: [*]). Proxy xs -> Integer
t3 _ = case Proxy :: Proxy (Length xs) of
         p@(_ :: Proxy l) -> case unsafeKnownConstr @(KnownNat l) of
                             Refl -> natVal @l p

具体来说,
    • Could not deduce (KnownNat n0) arising from a use of ‘natVal’
      from the context: KnownNat n0 ~ KnownNat (Length xs)
        bound by a pattern with constructor:
                   Refl :: forall k (a :: k). a :~: a,
                 in a case alternative
...
      The type variable ‘n0’ is ambiguous
GHC (8.10.4) 在这里提示什么?或者,是否有另一种方法来提取这些未知的 Nats?

最佳答案

你可以这样做:

t4 :: forall n xs. (n ~ Length xs, KnownNat n) => Proxy xs -> Integer
t4 _ = natVal $ Proxy @n
这表示您的调用者必须知道类型级别列表 xs足以完全解决 Length xs到固定值,他们将能够产生一个 KnownNat instance.1 但在里面 t4你可以对你不知道的列表进行操作。
λ t4 $ Proxy @[Int, Char, Bool]
3
it :: Integer

您的尝试没有成功,因为 unsafeKnownConstr有类型 forall c n. c :~: KnownNat n .它 promise 对于任何约束 c你喜欢,它可以证明约束等于KnownNat n对于任何 n你喜欢。
除了这显然是一个虚假的 promise 之外,当您使用 unsafeKnownConstr @(KnownNat l) 时你只是在设置 c . n仍然是一个可以实例化为任何东西的类型变量。 GHC 不知道该选什么 n ;这就是 GHC 提示的模棱两可的类型变量。实际上,您已经撒谎并告诉它任何任意选择的n等于列表的长度,但您实际上并没有选择 n使用,所以 GHC 无法判断是什么 KnownNat你想(错误地)考虑的字典 KnownNat字典 Length xs .
如果您修复 unsafeKnownConstr 的第二个类型参数,那么你可以得到这样的东西来编译:
t3 :: forall (xs :: [*]). Proxy xs -> Integer
t3 _ = case Proxy :: Proxy (Length xs) of
         p@(_ :: Proxy l) -> case unsafeKnownConstr @(KnownNat l) @17928 of
                             Refl -> natVal @l p
然后允许您在 GHCI 中执行此操作:
λ t3 $ Proxy @[Int, Char, Bool]
17928
it :: Integer
但是,无论您选择什么值,都会不安全地强制 KnownNat约束对您不会很有用,因为它们确实包含信息:已知值 Nat !

1 或者他们也可以尝试解决它并通过他们自己的类型将约束传递给他们自己的调用者。

关于haskell - 从任意未知 Nats 中提取值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68241723/

相关文章:

haskell - 将数字字符串转换为整数

haskell - 具有重载数字和字符串文字的类型类多态性

haskell - 为什么 `fmap (take 10) . sequence . fmap return $ [1..]::m [Int]` 只适用于某些 monad?

haskell - 类型族 - 不能派生 Base Int?

objective-c - 这种语法格式是否正确 : "PI/(double) (i - j)" in C?

sql - Oracle中的 "NUMBER"和 "NUMBER(*,0)"是否相同?

haskell - 测试函数的类型

c# - 我可以规定 C# 类型参数只能是接口(interface)类型吗?

java - 相同类型的类型不匹配

c# - 将方法的类型参数限制为另一种类型实现的接口(interface)