尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

类型的类型是什么?haskell-exercises KindSignatures完全指南,一次搞懂Type与Constraint

类型的类型是什么?haskell-exercises KindSignatures完全指南,一次搞懂Type与Constraint 类型的类型是什么haskell-exercises KindSignatures完全指南一次搞懂Type与Constraint【免费下载链接】haskell-exercisesA little course to learn about some of the more obscure GHC extensions.项目地址: https://gitcode.com/gh_mirrors/has/haskell-exercises类型type居然还有类型没错这就是 Haskell 中既晦涩又强大的 GHC 扩展之一KindSignatures。haskell-exercises 是一个循序渐进学习 GHC 高级扩展的开源练习项目总共 10 个章节KindSignatures 正是其中第三课的核心内容。本文将从零讲起帮你理解类型的类型Kind这个概念搞懂Type 与 Constraint两种种类kind的区别学会使用 KindSignatures 扩展为类型参数标注种类让 GHC 编译器在编译期帮你挡住更多错误。什么是 Kind先搞懂类型的类型这个概念在 Haskell 中3 :: IntNothing :: Maybe (IO String)每个值都有自己的类型。那类型本身有没有类型呢有这个类型的类型就叫做Kind种类。我们平时使用的绝大多数类型都属于同一个种类Type早期写作*。比如Int、Bool、String、Maybe Int它们的种类都是Type。你可以把它理解为有运行时值的类型。但有些东西比较特殊比如Maybe本身——它不是一个完整的类型而是一个类型构造器。你会问Maybe 什么的。从种类的角度看Maybe :: Type - TypeMaybe像是一个类型级函数给它一个类型Int就得到类型Maybe Int给它Bool就得到Maybe Bool。同理Either的种类是Type - Type - Type二元元组构造器(,)也一样。一句话总结值有类型类型有种类Kind。为什么要用 KindSignatures一条报错引发的思考如果没有 KindSignatures 扩展GHC 默认假设类型类typeclass的所有参数种类都是Type。于是当你写下下面这行代码时instance OfKindType MaybeGHC 会毫不留情地报错• Expecting one more argument to Maybe Expected a type, but Maybe has kind * - *为什么因为OfKindType的参数被 GHC 假定为Type而Maybe的种类是Type - Type两者对不上。虽然 GHC 有时候能靠方法签名自己推断比如fmap :: (a - b) - f a - f b中出现的是f a而不是单独的fGHC 由此能推出f :: Type - Type。但依赖这种猜终究不可靠显式声明才是正道。KindSignatures 扩展就是用来解决这个问题的它允许你在类型类声明中直接写出类型参数的种类把该参数必须是什么种类明明白白地告诉 GHC。KindSignatures 的用法给类型参数标注种类开启扩展后你可以在类声明中这样写class OfKindTypeToType (a :: Type - Type)这里(a :: Type - Type)就是一条类型签名Kind Signature它声明OfKindTypeToType接受的参数种类必须是Type - Type。于是下面这些实例全部合法instance OfKindTypeToType Maybe instance OfKindTypeToType [] instance OfKindTypeToType (Either e) instance OfKindTypeToType ((,) a) instance OfKindTypeToType IO试试删掉种类签名你会立刻看到整片整片的种类错误——这就是 KindSignatures 的价值把错误提前到编译期。除此之外KindSignatures 还是极佳的代码文档。比如这样写读代码的人一眼就知道参数是个双参类型构造器class MyFavouriteBifunctor (element :: (Type - Type - Type)) instance MyFavouriteBifunctor Either instance MyFavouriteBifunctor (,)Type 与 Constraint两种最重要的种类怎么选除了Type还有另一种极其重要的种类Constraint也就是约束的种类。看这个例子class Whoa (constraint :: Constraint) instance Whoa (Eq Int) instance Whoa (Show String) instance Whoa ()Eq Int、Show String这些**约束constraint**的种类就是Constraint。回想一下带约束的函数签名f :: (Show a, Eq a) a - a - String左边那一串全都是Constraint种类的成员。可能你会疑惑()不应该是类型吗没错在 Haskell 中()是重载的在Constraint种类下它代表空约束一个永远为真的约束。看到g :: () a - a这种写法你就知道它的约束部分永远满足。一句话区分Type是有什么值的种类Constraint是需要满足什么条件的种类。搞懂这两者后面学习 ConstraintKinds、TypeFamilies 就轻松多了。想深入了解可以阅读项目中的 ConstraintKinds.hs。动手练习haskell-exercises 第三课 10 道题理论学完就该动手了haskell-exercises 第三课的练习文件在 Exercises.hs里面有 10 道精心设计的题目难度逐渐升级第 14 题给Maybe、Either、(,,)、(-)编写实例你需要判断它们各自的种类是Type - Type还是更复杂的多层箭头第 56 题[[Int]]、Either () (Maybe (IO String))这类已经填满的类型参数种类是什么第 79 题Eq Int、Show、Functor Maybe——从普通类型跨入Constraint种类开始挑战你的理解第 10 题故意留了一个种类错误的实例(Monad m, Eq m, Show a)考考你三部分里哪两个种类是对的到底哪里坏了练习的完整讲解源码在 KindSignatures.hs卡住时可以参考但强烈建议先自己试记住让 GHC 报错再看错误信息才是最快的学法。快速上手haskell-exercises 的安装与运行方法想跟着练习很简单先克隆仓库git clone https://gitcode.com/gh_mirrors/has/haskell-exercises然后进入第三课目录用 Cabal 或 Stack 打开 REPL 交互练习cd 03-KindSignatures cabal repl # 或者 stack repl构建整个项目则运行cabal build # 或者 stack build追求极致效率的话可以安装ghcid实现保存即检查配合 REPL 使用效果更佳。项目的构建配置在 exercise03.cabal依赖非常简单只有base无需额外折腾。✅学习路线KindSignatures 之后还能学什么KindSignatures 是通往高级 Haskell 类型的基石haskell-exercises 这个 10 课时的项目专门为此设计后面的章节会反复用到它DataKinds把数据构造器提升为类型配合 KindSignatures 实现类型级编程见 DataKinds.hsConstraintKinds把约束当成一等公民操作见 ConstraintKinds.hsPolyKinds、TypeFamilies、GADTs多态种类、类型族、广义代数数据类型……层层递进逐步把能用类型表达的事情推到极致。可以说每当你想在类型系统里做点复杂的事情KindSignatures 几乎都是必开扩展之一。花一两个小时做完这 10 道题你对 Haskell 类型系统的理解绝对会上一个台阶。现在就打开仓库从第三课开始你的类型级之旅吧【免费下载链接】haskell-exercisesA little course to learn about some of the more obscure GHC extensions.项目地址: https://gitcode.com/gh_mirrors/has/haskell-exercises创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表