我可以拥有一个未知的 KnownNat 吗?
Can I have an unknown KnownNat?
我想知道关于KnownNats
我是否可以吃我的蛋糕。我可以编写使用可能同时是 KnownNats
和 UnknownNats
的 Nats
的代码吗(SomeNats
?)。
例如,如果我有一个依赖类型的向量 Vec (n :: Nat) a
,如果大小在编译和运行时已知,我是否可以编写既能工作的代码?事情是我不想复制静态和动态大小 "things" 的整个代码。而且我不想通过在数据结构中存储大小来失去静态保证。
编辑
安德拉斯·科瓦奇的回答:
我的具体用例是从磁盘读取图像(幸好大小固定)然后从中提取补丁,所以基本上我有一个函数 extractPatch :: (KnownNat w2, KnownNat h2) => Image w1 h1 a -> Patch w2 h2
a 其中 Image
和 Patch
是常见 Mat (w :: Nat) (h :: Nat)
类型的实例。
如果我不知道图像大小,我将不得不在 "runtime types" 中对其进行编码。只是想知道。
这里有一些可能有趣的东西...
{-# LANGUAGE DataKinds, KindSignatures, ScopedTypeVariables #-}
import GHC.TypeLits
import Data.Proxy
data Bar (n :: Nat) = Bar String deriving Show
bar :: KnownNat n => Bar n -> (String, Integer)
bar b@(Bar s) = (s, natVal b)
好吧,这很没有意义。但这是使用 KnownNat
获取编译时信息的示例。但是由于 GHC.TypeLits
中的其他功能,它也可以与 运行 时间信息一起使用。
只需将其添加到上面的代码中,然后尝试一下。
main :: IO ()
main = do
i <- readLn
let Just someNat = someNatVal i
case someNat of
SomeNat (_ :: Proxy n) -> do
let b :: Bar n
b = Bar "hello!"
print $ bar b
让我们分解一下这里发生的事情。
- 从标准输入读取
Integer
。
- 从中创建一个
SomeNat
类型的值,如果输入为负,则模式匹配失败。对于这样一个简单的示例,处理该错误只会成为阻碍。
- 这才是真正的魔法。使用
case
表达式进行模式匹配,使用 ScopedTypeVariables
将(静态未知的)Nat
类型绑定到类型变量 n
.
- 最后,创建一个
Bar
值,并将特定的 n
作为其类型变量,然后用它做一些事情。
我想知道关于KnownNats
我是否可以吃我的蛋糕。我可以编写使用可能同时是 KnownNats
和 UnknownNats
的 Nats
的代码吗(SomeNats
?)。
例如,如果我有一个依赖类型的向量 Vec (n :: Nat) a
,如果大小在编译和运行时已知,我是否可以编写既能工作的代码?事情是我不想复制静态和动态大小 "things" 的整个代码。而且我不想通过在数据结构中存储大小来失去静态保证。
编辑
安德拉斯·科瓦奇的回答:
我的具体用例是从磁盘读取图像(幸好大小固定)然后从中提取补丁,所以基本上我有一个函数 extractPatch :: (KnownNat w2, KnownNat h2) => Image w1 h1 a -> Patch w2 h2
a 其中 Image
和 Patch
是常见 Mat (w :: Nat) (h :: Nat)
类型的实例。
如果我不知道图像大小,我将不得不在 "runtime types" 中对其进行编码。只是想知道。
这里有一些可能有趣的东西...
{-# LANGUAGE DataKinds, KindSignatures, ScopedTypeVariables #-}
import GHC.TypeLits
import Data.Proxy
data Bar (n :: Nat) = Bar String deriving Show
bar :: KnownNat n => Bar n -> (String, Integer)
bar b@(Bar s) = (s, natVal b)
好吧,这很没有意义。但这是使用 KnownNat
获取编译时信息的示例。但是由于 GHC.TypeLits
中的其他功能,它也可以与 运行 时间信息一起使用。
只需将其添加到上面的代码中,然后尝试一下。
main :: IO ()
main = do
i <- readLn
let Just someNat = someNatVal i
case someNat of
SomeNat (_ :: Proxy n) -> do
let b :: Bar n
b = Bar "hello!"
print $ bar b
让我们分解一下这里发生的事情。
- 从标准输入读取
Integer
。 - 从中创建一个
SomeNat
类型的值,如果输入为负,则模式匹配失败。对于这样一个简单的示例,处理该错误只会成为阻碍。 - 这才是真正的魔法。使用
case
表达式进行模式匹配,使用ScopedTypeVariables
将(静态未知的)Nat
类型绑定到类型变量n
. - 最后,创建一个
Bar
值,并将特定的n
作为其类型变量,然后用它做一些事情。