我可以拥有一个未知的KnownNat吗?

时间:2015-06-10 09:39:47

标签: haskell dependent-type

我想知道我是否可以吃蛋糕而且也吃KnownNats。我可以编写使用可能同时为NatsKnownNatsUnknownNats的{​​{1}}的代码吗?

例如,如果我有一个依赖类型的向量SomeNats,我是否可以编写在编译和运行时已知大小的代码?事情是,我不想复制静态和动态大小的“事物”的整个代码。而且我不希望通过在数据结构中存储大小来丢失静态保证。

修改

回答AndrásKovács:

我的具体用例是从磁盘读取图像(幸运的是固定大小),然后从中提取补丁,所以基本上我有一个函数Vec (n :: Nat) a a extractPatch :: (KnownNat w2, KnownNat h2) => Image w1 h1 a -> Patch w2 h2和{{1}是常见Image类型的实例。

如果我不知道图像大小,我必须在“运行时类型”中对其进行编码。只是想知道。

1 个答案:

答案 0 :(得分:9)

这里有一些有趣的东西......

{-# 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

让我们分解这里发生的事情。

  1. 从stdin。
  2. 中读取Integer
  3. 从中创建一个SomeNat - 类型的值,如果输入为负,则模式匹配失败。对于这样一个简单的例子,处理该错误只是妨碍了。
  4. 这是真正的魔力。模式匹配case表达式,使用ScopedTypeVariables将(静态未知的)Nat - kinded类型绑定到类型变量n
  5. 最后,使用该特定Bar作为其类型变量创建n值,然后使用它进行操作。
相关问题