Haskell 在编译时生成用于约束检查的类型级别NAT
我试图在编译时在类型级别表示一个整数值,这样我就可以根据一些约束检查它 我希望DSL的用户不必编写以下内容:Haskell 在编译时生成用于约束检查的类型级别NAT,haskell,types,Haskell,Types,我试图在编译时在类型级别表示一个整数值,这样我就可以根据一些约束检查它 我希望DSL的用户不必编写以下内容: five = inc $ inc $ inc $ inc $ inc $ zero five = inc $ inc $ inc $ inc $ inc $ zero 因此,我一直试图创建一个函数,将该值提升到类型级别 即 这就是我迄今为止所尝试的: data Z data S a data IntNat a = IN Int zero = (IN 0 :: IntNat Z)
five = inc $ inc $ inc $ inc $ inc $ zero
five = inc $ inc $ inc $ inc $ inc $ zero
因此,我一直试图创建一个函数,将该值提升到类型级别
即
这就是我迄今为止所尝试的:
data Z
data S a
data IntNat a = IN Int
zero = (IN 0 :: IntNat Z)
inc :: IntNat a -> IntNat (S a)
inc (IN i) = (IN (i + 1))
fromInt :: Int -> IntNat a
fromInt 0 = (IN 0 :: IntNat Z)
fromInt n = inc (fromInt (n - 1))
但是,这失败了,因为我没有足够通用的IntNat表示,intnatz~/~intnatsz
这种方法通常是有缺陷的,还是需要在类型族/类型类中包含sz
这方面的另一个经典示例是在使用类型级别的长度注释向量时生成特定长度的向量。该函数应该解决与我相同的问题。由于Haskell没有依赖类型,因此无法将值级别
Int
提升到类型级别。根据您的用例,您有几个近似选项
使用连续传球方式
使用存在类型
利用现有的类型级文字
我希望DSL的用户不必编写以下内容:
five = inc $ inc $ inc $ inc $ inc $ zero
five = inc $ inc $ inc $ inc $ inc $ zero
这是一种您可以轻松编写准语言的东西,但在本例中,您可以使用GHC对类型级Nat文本的支持,使用类型族(即类型级函数)将其转换为表示形式
你也会得到一些东西,比如类型级别的添加等等
*Main GHC.TypeLits Data.Proxy> :t fromNat (Proxy :: Proxy 5)
fromNat (Proxy :: Proxy 5) :: Proxy (S (S (S (S (S Z)))))
*Main GHC.TypeLits Data.Proxy> :t fromNat (Proxy :: Proxy (3 + 2))
fromNat (Proxy :: Proxy (3 + 2)) :: Proxy (S (S (S (S (S Z)))))
编辑:Anders首先给出答案,但将其作为替代实现这在Haskell中是不可能的,因为它需要依赖类型。
fromInt
没有有效的类型签名。Haskell没有依赖类型吗?不,不是你需要的那种。如果你阅读了你链接的文章,你会注意到它不允许你所需要的类型签名。你应该添加更多的上下文来解释为什么你需要这样做。一般来说,有两种不同的方法可以实现这一点:使用类型族(作为类型级函数)或使用模板Haskell(为类型表达式生成代码)。@leftaroundabout我使用模板HaskellfromInt
将生成inc$inc$…
表达式?类型族方法是什么?我认为核心问题是,对于任何给定的函数,结果类型必须是固定的?
five = inc $ inc $ inc $ inc $ inc $ zero
{-# LANGUAGE DataKinds, TypeOperators, KindSignatures, TypeFamilies, UndecidableInstances #-}
import GHC.TypeLits
import Data.Proxy
data Z
data S a
type family FromNat (n :: Nat) where
FromNat 0 = Z
FromNat n = S (FromNat (n - 1))
fromNat :: Proxy n -> Proxy (FromNat n)
fromNat _ = Proxy
*Main GHC.TypeLits Data.Proxy> :t fromNat (Proxy :: Proxy 5)
fromNat (Proxy :: Proxy 5) :: Proxy (S (S (S (S (S Z)))))
*Main GHC.TypeLits Data.Proxy> :t fromNat (Proxy :: Proxy (3 + 2))
fromNat (Proxy :: Proxy (3 + 2)) :: Proxy (S (S (S (S (S Z)))))