固定长度和类型文字的列表
Lists of fixed length and type literals
我正在尝试为 Haskell 中的固定长度列表定义类型。当我使用标准方法将自然数编码为一元类型时,一切正常。但是,当我尝试在 GHC 的类型文字上构建所有内容时,我 运行 遇到了很多问题。
我对所需列表类型的第一次尝试是
data List (n :: Nat) a where
Nil :: List 0 a
(:>) :: a -> List n a -> List (n+1) a
不幸的是,它不允许编写类型为
的 zip 函数
zip :: List n a -> List n b -> List n (a,b)
我可以通过从 (:>)
类型中的类型变量 n
中减去 1 来解决这个问题:
data List (n :: Nat) a where
Nil :: List 0 a
(:>) :: a -> List (n-1) a -> List n a -- subtracted 1 from both n's
接下来,我尝试定义一个追加函数:
append :: List n1 a -> List n2 a -> List (n1 + n2) a
append Nil ys = ys
append (x :> xs) ys = x :> (append xs ys)
不幸的是,GHC 告诉我
Couldn't match type ‘(n1 + n2) - 1’ with ‘(n1 - 1) + n2’
将约束 ((n1 + n2) - 1) ~ ((n1 - 1) + n2)
添加到签名并不能解决问题,因为 GHC 抱怨
Could not deduce ((((n1 - 1) - 1) + n2) ~ (((n1 + n2) - 1) - 1))
from the context (((n1 + n2) - 1) ~ ((n1 - 1) + n2))
现在,我显然陷入了某种无限循环。
所以,我想知道是否可以使用类型文字为固定长度的列表定义类型。我什至可能正是出于这个目的而监督图书馆吗?基本上,唯一的要求是我想写 List 3 a
而不是 List (S (S (S Z))) a
.
类型级别的数字文字还没有我们可以进行归纳的结构,内置的约束求解器只能找出最简单的情况。目前最好坚持使用 Peano naturals。
但是,我们仍然可以使用文字作为语法糖。
{-# LANGUAGE
UndecidableInstances,
DataKinds, TypeOperators, TypeFamilies #-}
import qualified GHC.TypeLits as Lit
data Nat = Z | S Nat
type family Lit n where
Lit 0 = Z
Lit n = S (Lit (n Lit.- 1))
现在您可以写 List (Lit 3) a
而不是 List (S (S (S Z))) a
。
这不是真正的答案。
使用 https://hackage.haskell.org/package/ghc-typelits-natnormalise-0.2 ,这个
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-}
import GHC.TypeLits
data List (n :: Nat) a where
Nil :: List 0 a
(:>) :: a -> List n a -> List (n+1) a
append :: List n1 a -> List n2 a -> List (n1 + n2) a
append Nil ys = ys
append (x :> xs) ys = x :> (append xs ys)
...编译,显然是正确的。
我正在尝试为 Haskell 中的固定长度列表定义类型。当我使用标准方法将自然数编码为一元类型时,一切正常。但是,当我尝试在 GHC 的类型文字上构建所有内容时,我 运行 遇到了很多问题。
我对所需列表类型的第一次尝试是
data List (n :: Nat) a where
Nil :: List 0 a
(:>) :: a -> List n a -> List (n+1) a
不幸的是,它不允许编写类型为
的 zip 函数zip :: List n a -> List n b -> List n (a,b)
我可以通过从 (:>)
类型中的类型变量 n
中减去 1 来解决这个问题:
data List (n :: Nat) a where
Nil :: List 0 a
(:>) :: a -> List (n-1) a -> List n a -- subtracted 1 from both n's
接下来,我尝试定义一个追加函数:
append :: List n1 a -> List n2 a -> List (n1 + n2) a
append Nil ys = ys
append (x :> xs) ys = x :> (append xs ys)
不幸的是,GHC 告诉我
Couldn't match type ‘(n1 + n2) - 1’ with ‘(n1 - 1) + n2’
将约束 ((n1 + n2) - 1) ~ ((n1 - 1) + n2)
添加到签名并不能解决问题,因为 GHC 抱怨
Could not deduce ((((n1 - 1) - 1) + n2) ~ (((n1 + n2) - 1) - 1))
from the context (((n1 + n2) - 1) ~ ((n1 - 1) + n2))
现在,我显然陷入了某种无限循环。
所以,我想知道是否可以使用类型文字为固定长度的列表定义类型。我什至可能正是出于这个目的而监督图书馆吗?基本上,唯一的要求是我想写 List 3 a
而不是 List (S (S (S Z))) a
.
类型级别的数字文字还没有我们可以进行归纳的结构,内置的约束求解器只能找出最简单的情况。目前最好坚持使用 Peano naturals。
但是,我们仍然可以使用文字作为语法糖。
{-# LANGUAGE
UndecidableInstances,
DataKinds, TypeOperators, TypeFamilies #-}
import qualified GHC.TypeLits as Lit
data Nat = Z | S Nat
type family Lit n where
Lit 0 = Z
Lit n = S (Lit (n Lit.- 1))
现在您可以写 List (Lit 3) a
而不是 List (S (S (S Z))) a
。
这不是真正的答案。
使用 https://hackage.haskell.org/package/ghc-typelits-natnormalise-0.2 ,这个
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# OPTIONS_GHC -fplugin GHC.TypeLits.Normalise #-}
import GHC.TypeLits
data List (n :: Nat) a where
Nil :: List 0 a
(:>) :: a -> List n a -> List (n+1) a
append :: List n1 a -> List n2 a -> List (n1 + n2) a
append Nil ys = ys
append (x :> xs) ys = x :> (append xs ys)
...编译,显然是正确的。