单遍历软件包使用MinLen
的类型级别Peano编号。我可以使用链式Succ
s构建它们:
toMinLen [1,2,3] :: Maybe (MinLen (Succ (Succ Zero)) [Int])
但这很快就会失控:
toMinLen [1,2,3] :: Maybe (MinLen (Succ (Succ (Succ (Succ (Succ Zero))))) [Int])
有没有方便的方法来构建更大的Peano数字?我看到GHC有一个TypeLiterals扩展,但我不确定我是否可以在这里使用它。或者,我可以创建像:
这样的同义词type One = Succ Zero
type Two = Succ One
等等;做某事已经存在于某个地方了?
答案 0 :(得分:4)
TypeLits
非常适合类型级数字。此外,它很容易只用于语法糖,并保持底层库特定的实现不变。
{-# LANGUAGE
UndecidableInstances, TypeFamilies,
DataKinds, TypeOperators #-}
import qualified GHC.TypeLits as TL
data Nat = Zero | Succ Nat
newtype MinLen (n :: Nat) a = MinLen a
我们必须定义一个将文字转换为数字类型的类型系列:
type family Lit (n :: TL.Nat) :: Nat where
Lit 0 = Zero
Lit n = Succ (Lit (n TL.- 1))
现在,只要您需要Lit n
字面值,就可以使用Nat
。在GHCi:
>:kind! MinLen (Lit 3)
MinLen (Lit 3) :: * -> *
= MinLen ('Succ ('Succ ('Succ 'Zero)))
答案 1 :(得分:2)
有一个包这类的东西:type-level。这有点令人生畏,我还没有真正探索过它。但是你不应该需要那么大的力量,所以你可以自己动手。
如果您愿意使用UndecidableInstances
,事情就很容易了。大致相似的东西(我不确切知道该库中的自然界是如何定义的;如果它不使用DataKinds
,您可能必须使用*
种而不是Nat
种类,您可能需要写'Succ
和'Zero
而不是Succ
和Zero
- 我对此不太清楚方面):
{-# LANGUAGE UndecidableInstances, TypeFamilies, DataKinds, TypeOperators #-}
module TAR where
-- You wouldn't actually use this line, because the library
-- provides the naturals
data Nat = Zero | Succ Nat
-- Digits and Ten to get things started
type One = Succ Zero
type Two = Succ One
type Three = Succ Two
type Four = Succ Three
type Five = Succ Four
type Six = Succ Five
type Seven = Succ Six
type Eight = Succ Seven
type Nine = Succ Eight
type Ten = Succ Nine
type family Plus (a::Nat) (b::Nat) where
Plus Zero n = n
Plus (Succ m) n = Plus m (Succ n)
type family Times (a::Nat) (b::Nat) where
Times Zero n = Zero
Times (Succ m) n = Plus n (Times m n)
type Decimal (a::[Nat]) = Decimal' a Zero
type family Decimal' (a::[Nat]) (n::Nat) where
Decimal' '[] n = n
Decimal' (a ': bs) n = Decimal' bs (Plus a (Times Ten n))
然后你可以写点像
Decimal '[One, Two, Five]
表示125。
答案 2 :(得分:1)