You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell中如何在类型签名指定任意长度的有序SNat列表?

为任意长度的SNat列表实现严格降序的类型约束

你可以通过递归类型家族定义一个通用约束,确保任意长度的SNat列表是严格降序的,无需为每个列表长度手动编写重复约束。以下是完整实现:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE FlexibleContexts #-}

module Main where 
import Data.Kind

-- 自然数类型定义
data Nat = Z | S Nat deriving Show
type One = S Z
type Two = S One
type Three = S Two

-- 自然数的单例类型
data SNat (n :: Nat) where
  SZ :: SNat Z
  SS :: SNat n -> SNat (S n)

-- 二元大于约束:Gt a b 表示 a > b
type Gt :: Nat -> Nat -> Constraint
type family Gt n m where
  Gt Z _ = 'True ~ 'False  -- Z不可能大于任何数
  Gt _ Z = ()               -- 任何数都大于Z
  Gt (S n) (S m) = Gt n m   -- 递归比较前驱

-- 从SNat类型列表中提取对应的Nat类型列表
type ExtractNats :: [Type] -> [Nat]
type family ExtractNats xs where
  ExtractNats '[] = '[]
  ExtractNats (SNat n : xs) = n : ExtractNats xs

-- 约束整个Nat列表是严格降序的
type StrictlyDescending :: [Nat] -> Constraint
type family StrictlyDescending ns where
  StrictlyDescending '[] = ()               -- 空列表满足约束
  StrictlyDescending '[_] = ()              -- 单元素列表满足约束
  StrictlyDescending (n : m : ns) = (Gt n m, StrictlyDescending (m : ns))  -- 递归检查相邻元素

-- HList定义
type HList :: [Type] -> Type
data HList xs where
  HNil :: HList '[]
  (:&) :: x -> HList xs -> HList (x : xs)
infixr 5 :&

-- 通用函数:仅接受严格降序的SNat列表,返回最后一个元素
gn :: (StrictlyDescending (ExtractNats xs)) => HList xs -> SNat n
gn HNil = error "空列表无元素返回"  -- 实际因约束不会触发
gn (x :& HNil) = x
gn (_ :& xs) = gn xs

关键组件说明

  • ExtractNats类型家族:把HList的类型参数(比如[SNat Three, SNat Two, SNat One])转换为对应的自然数类型列表[Three, Two, One],方便后续约束检查。
  • StrictlyDescending类型家族:递归遍历自然数类型列表,确保每一对相邻元素都满足Gt约束(前一个数大于后一个),从而保证整个列表是严格降序的。
  • gn函数:通过StrictlyDescending (ExtractNats xs)约束,自动对任意长度的SNat列表进行类型检查,非法的非降序列表会被编译器直接拒绝。

示例验证

  • 合法调用(严格降序):
    -- 类型检查通过
    test1 = gn (SS (SS (SS SZ)) :& SS (SS SZ) :& SS SZ :& HNil)  -- Three > Two > One
    
  • 非法调用(非降序):
    -- 编译器报错:无法满足 Gt One Two 约束
    test2 = gn (SS SZ :& SS (SS SZ) :& HNil)  -- One < Two,违反约束
    

内容的提问来源于stack exchange,提问作者Evg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 17:17:46