更新时间:2023-01-19 18:51:47
{ - #LANGUAGE DataKinds,KindSignatures,ScopedTypeVariables# - }
import GHC.TypeLits
import Data.Proxy
data Bar(n :: Nat)= Bar字符串派生Show
bar :: KnownNat n =>栏n - > (String,Integer)
bar b @(Bar s)=(s,natVal b)
KnownNat 获取编译时信息的例子。但是感谢 GHC.TypeLits
中的其他函数,它也可以用于运行时信息。
只需将它添加到上面的代码中,然后试试。
main :: IO()
main = do
i 让SomeNat = someNatVal i
case someNat
SomeNat(_ :: Proxy n) - >做
让b :: Bar n
b =酒吧hello!
print $ bar b
让我们来分析这里发生的事情。
整数
。 SomeNat
-typed值,如果输入是负值,则失败模式匹配。对于这样一个简单的例子来说,处理这个错误就会成为现实。 ScopedTypeVariables
与 case
表达式进行模式匹配,以绑定(静态未知) Nat $ c> -kinded类型转换为类型变量 n
。
Bar
值与该特定 n
作为其类型变量,然后对其进行处理。
I wonder if I can have my cake and eat it too regarding KnownNats
. Can I write code that uses Nats
that may be both KnownNats
and UnknownNats
(SomeNats
?).
For example if I have a dependently typed vector Vec (n :: Nat) a
, can I write code that works both if the size is known at compile and at runtime? Thing is that I don't want to duplicate the whole code for statically and dynamically sized "things". And I don't want to lose static guarantees by storing sizes in the data structure.
Answer to András Kovács:
My specific usecase is reading images from disk (which are luckily of fixed size) and then extracting patches from that, so basically I have a function extractPatch :: (KnownNat w2, KnownNat h2) => Image w1 h1 a -> Patch w2 h2
a where both Image
and Patch
are instances of a common Mat (w :: Nat) (h :: Nat)
a type.
If I wouldn't know the image size I would have to encode this in "runtime types". Just wondering.
Here's something potentially interesting...
{-# 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)
Ok, it's very pointless. But it's an example of using KnownNat
to get at compile-time information. But thanks to the other functions in GHC.TypeLits
, it can be used with run-time information as well.
Just add this on to the above code, and try it out.
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
Let's break down what happens here.
Integer
from stdin.SomeNat
-typed value from it, failing the pattern-match if the input was negative. For such a simple example, handling that error just gets in the way.case
expression, using ScopedTypeVariables
to bind the (statically unknown) Nat
-kinded type to the type variable n
.Bar
value with that particular n
as its type variable and then do things with it.