组合扩展的威力:从haskell-exercises学习GADTs+DataKinds+TypeFamilies协同作战

发布时间:2026/10/6 20:25:43

组合扩展的威力:从haskell-exercises学习GADTs+DataKinds+TypeFamilies协同作战 组合扩展的威力从haskell-exercises学习GADTsDataKindsTypeFamilies协同作战【免费下载链接】haskell-exercisesA little course to learn about some of the more obscure GHC extensions.项目地址: https://gitcode.com/gh_mirrors/has/haskell-exercises学习 Haskell 时很多人都会遇到一个瓶颈普通类型系统已经用得很熟但面对GADTs、DataKinds、TypeFamilies这些 GHC 扩展却不知从何下手。haskell-exercises正是一套为这类学习者量身定制的练习课程它用一个接一个的微型项目带你把把错误挡在编译期这件事做到极致。本文将带你拆解这三个核心扩展并展示它们组合起来时的惊人威力。为什么单独学扩展很容易学废很多教程喜欢把扩展一个个单独讲但真实项目里它们几乎总是抱团出现。GADTs 给了你为每个构造器定制类型的自由DataKinds 让数据提升到类型层面TypeFamilies 则让类型本身可以计算。单独看每个都像是魔术组合起来才是真正的工程利器。haskell-exercises 的目录结构就是按扩展逐一组织的从01-GADTs一直到10-FunctionalDependencies每个练习目录都包含两个核心文件讲解版和练习版。例如01-GADTs/src/GADTs.hs是概念讲解而01-GADTs/src/Exercises.hs则是留给你的填空题答案藏在answers分支里。第一块拼图GADTs 让类型参数活起来 普通代数数据类型ADT有个限制所有构造器必须返回同一个类型。而广义代数数据类型GADTs打破了这个规则——每个构造器可以精确指定自己的返回类型还能在构造器里携带约束。看一个经典例子来自01-GADTs/src/GADTs.hsdata ShowList where ShowNil :: ShowList ShowCons :: Show a a - ShowList - ShowList这里ShowCons里藏着一个存在类型a它可以是任意类型只要实现了Show。于是你可以写出ShowCons Tom (ShowCons 25 (ShowCons True ShowNil))这种混合类型的列表——类型不同没关系只要都能被show出来就行。GADTs 另一个惊人能力是让类型检查器帮你排除不可能。同一个文件中MysteryBox和HList练习展示了当模式匹配某个构造器时GHC 能自动知道其他分支不可能发生从而允许你写出不需要 Maybe 的 total function。第二块拼图DataKinds 把数据升维到类型层 如果说 GADTs 是类型参数根据构造器变化那 DataKinds 就是值也能变成类型。打开04-DataKinds/src/DataKinds.hs你会看到一颗自然数的提升data Natural Zero | Successor Natural开启DataKinds后Natural同时成为一个kindZero和Successor变成类型层面的构造器。更妙的是我们可以用它给列表装上长度data Vector (length :: Natural) (a :: Type) where VNil :: Vector Zero a VCons :: a - Vector n a - Vector (Successor n) a于是长度信息被写进了类型head函数不再需要Maybe——因为类型为Vector (Successor n) a的值不可能是空列表。甚至zip函数原本需要四种情况匹配现在类型检查器能证明长度相等的两个向量要么都是空、要么都是非空代码直接砍掉一半分支。第三块拼图TypeFamilies 让类型也会计算 ➕06-TypeFamilies/src/TypeFamilies.hs只用了寥寥几十行就讲清楚了类型族TypeFamilies的本质类型层面的函数。type family Add (x :: Nat) (y :: Nat) :: Nat where Add Z y y Add (S x) y S (Add x y)这套递归定义和值层面的add函数几乎一一对应。类型族还能和单例类型singleton配合让根据输入类型决定输出类型成为可能。比如定义一个类型层面的Not就可以写出not :: SBool input - SBool (Not input)——布尔值翻转后类型也跟着翻转。协同作战1 1 1 3 的经典案例 ⚔️单独的扩展已经很强但真正震撼的是它们的组合。在04-DataKinds的练习里你可以构建一个异构列表 HList它把每个元素的类型都记录在类型层面在06-TypeFamilies的练习里则要求你用类型族写出类型层面的加减法、比较、甚至素数筛。最能体现三者合力的场景是用类型做协议/状态机。DataKinds 练习中有个著名的例子设计一个文件操作Program类型在类型层面记录文件当前是否打开文件未打开时ReadFile、WriteFile根本构造不出来未打开文件时调用CloseFile编译直接报错程序结束时类型保证文件必然已经关闭。这就是让非法状态不可表示make illegal states unrepresentable的威力——过去要靠运行时检查和测试才能发现的 bug现在编译器直接帮你拦下了。类似的还有 GADTs 练习里的类型对齐函数列表TypeAlignedList它保证函数列表里前一个函数的输出类型恰好等于后一个函数的输入类型拼出composeTALs :: TypeAlignedList b c - TypeAlignedList a b - TypeAlignedList a c这样的安全组合。如何开始动手练习️这套课程的使用方式非常简单克隆仓库git clone https://gitcode.com/gh_mirrors/has/haskell-exercises进入任意练习目录例如01-GADTs/用cabal repl或stack repl进入交互环境也可以用ghcid -c stack repl实现保存即检查打开src/Exercises.hs把error Implement me!逐个替换成你的实现卡住时切到answers分支对照答案每个练习目录下的exercise*.cabal文件都已配置好所需的语言扩展你几乎不需要手动{-# LANGUAGE ... #-}专心解题即可。学习路线建议 ️如果你完全零基础建议按官方顺序推进先01-GADTs掌握存在类型与类型导向的模式匹配再03-KindSignatures理解 kind 的概念这是 DataKinds 的地基接着04-DataKinds体验类型层面的编程最后06-TypeFamilies学会类型计算。之后还有07-ConstraintKinds、08-PolyKinds等进阶扩展等你解锁。结语 ✨很多人觉得 Haskell 的进阶扩展华而不实但 haskell-exercises 用大量精心设计的练习证明当 GADTs、DataKinds、TypeFamilies 协同作战时你是在把程序员的直觉写成可编译的类型约束。编译通过的那一刻不仅意味着程序能跑更意味着你正在写的代码在逻辑上就是正确的。从复制仓库到写完第一道题整个过程可能只需要一个下午。但这一下午的收获会彻底改变你写类型的方式。【免费下载链接】haskell-exercisesA little course to learn about some of the more obscure GHC extensions.项目地址: https://gitcode.com/gh_mirrors/has/haskell-exercises创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/27 4:04:29

Agent 工具的按需加载(ToolSearch)

Agent 工具的按需加载(ToolSearch) 本文描述 ToolSearch 从"agent 绑定工具清单"到"将完整工具加载到 Agent 运行实例"的完整交互流程。ToolSearch 是 Agent 运行时默认绑定、始终可用的内置工具(设计为按需启用),LLM 通过它按需检索并加载业务工具;…

2026/10/5 10:24:54

Python元组操作全攻略:查询统计遍历和转换

元组的定义 元组(Tuple) 表示多个元素组成的序列,与列表类似,不同之处在于元组定义好后元素不能修改,常用于保存不同类型的数据。 元组有特定的应用场景,常用于存储一串信息,元素之间使用逗号分…

2026/10/6 20:24:41

2024年Win11+Ubuntu 22.04.1 LTS双系统安装与避坑指南

简介:这份文档面向已装Windows 11、希望再装Ubuntu 22.04.1 LTS组成双系统的用户,覆盖从环境检查到安装完成的全流程。内容包含查看BIOS与UEFI模式、下载ISO镜像、用Rufus制作启动U盘、压缩磁盘分区、BIOS启动项设置,以及安装时选择“与Windo…

2026/10/6 20:24:41

Windows 11 装 Ubuntu 22.04.1 LTS 双系统:UEFI 引导避坑指南

简介:这份文档面向已装好 Windows 11、想再装 Ubuntu 22.04.1 LTS 组建双系统的用户,尤其适合初次接触 UEFI 引导与磁盘分区的新手。内容围绕双系统安装全流程展开,涵盖基础环境检查、Rufus 启动盘制作、与 Windows Boot Manager 共存的安装方…

2026/10/6 20:24:41

轻量AI中台实战:用私有化大模型实现智能录入与对账

去年年底结账,财务主管把一摞打印出来的银行流水拍在桌上,说这个月有三十二笔款项对不上业务订单,业务那边又说,光是补齐客户名称和合同编号就加班了两晚。我当时听完只有一个想法:这不是人不够勤快的问题,…

2026/10/6 20:24:41

国产RFSOC+FPGA双芯宽带高速信号处理板设计实战

这阵子集中做了一块国产RFSOCFPGA双芯架构的宽带高速信号处理板,从方案评估、器件选型到回板调试、跑通数据链路,整套流程走下来,踩了不少坑,也积累了一些值得记录的经验。做这类板卡的人应该都有同感:单看RFSOC的集成…

2026/10/6 20:24:41

大模型评测平台落地方案:集成Coze-Loop与AllData的自动化评估体系

跑了一年多大模型的落地项目,我越来越认同一个判断:真正卡住AI应用落地的,往往不是模型本身的智商,而是“怎么看它到底行不行”这套评测机制。我们团队在AllData平台上集成了开源项目Coze-Loop,搭了一套大模型评测平台…

2026/10/6 20:19:40

System-1 判断模型接入 agent loop:MCP 工具链下的循环控制实践

1. 为什么我会想到把 System-1 判断模型塞进 agent loop 先说清楚这篇要聊的东西是什么。System-1 判断模型,指的是那种"看一眼就给结论"的快速决策模型——它不追求长链条推理,而是在极短时间内对当前状态做一个高置信度的判断,输…

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/6 4:01:51

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/6 17:46:51

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 0:03:23

MR25H40CDF+STM32F031C6工业级高可靠数据存储方案

1. 项目概述:为什么在工业现场非得用 MR25H40CDF 配 STM32F031C6 做数据存储?在工厂产线的 PLC 控制柜里、在风电变流器的散热片背面、在矿井监测终端的金属外壳下,你经常能看到一块指甲盖大小的黑色芯片——它既不是 Flash,也不是…

2026/10/6 0:03:23

MRAM+STM32工业断电数据保全实战指南

1. 项目概述:为什么在工业现场非得用 MR25H40CDF 配 STM32F031C6 做数据存储?在工厂产线的PLC柜里、在野外无人值守的环境监测终端里、在高速运转的包装机控制板上,你经常能看到一块指甲盖大小的黑色芯片,旁边贴着“MR25H40CDF”丝…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑