Haskell中如何表达`()`是所有非`Void`类型的‘子集’概念?
解决方案:为非Void类型提供默认值的替代方案
你想要让parseEOF返回任意非Void类型的“无信息”值,同时避免手动为所有类型实现自定义类型类的繁琐,这里有几种实用的方法:
方法一:复用Default类型类(推荐)
Haskell生态里有现成的data-default包,它定义了Default类型类,已经为绝大多数常用类型(Int、Bool、()、列表等)提供了默认值实例,完全符合你“无信息”值的需求(比如Int默认0,Bool默认False,列表默认空列表)。
直接改造你的代码:
import Data.Default (Default(..)) parseEOF :: Default n => Parser n parseEOF = Parser p where p [] = Just (def, "") p _ = Nothing
对于自定义类型,只需要简单派生或手动实现Default实例即可,比自己写NonVoid类省事得多:
data MyType = MyType String Int deriving (Show) instance Default MyType where def = MyType "" 0 -- 自定义无信息值
方法二:用Generic自动推导默认值
如果不想依赖第三方包,可以利用GHC的Generic扩展自动生成自定义类型的默认值,减少手动编写实例的工作量。
先定义基于Generic的辅助类:
{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE TypeOperators #-} import GHC.Generics class GenericDefault a where genericDef :: a -- 为通用表示类型实现默认值逻辑 class GGenericDefault f where ggenericDef :: f a instance GGenericDefault U1 where ggenericDef = U1 instance (GGenericDefault a, GGenericDefault b) => GGenericDefault (a :*: b) where ggenericDef = ggenericDef :*: ggenericDef instance GGenericDefault a => GGenericDefault (M1 i c a) where ggenericDef = M1 ggenericDef -- 为基础类型手动定义默认值 instance GenericDefault Int where genericDef = 0 instance GenericDefault Bool where genericDef = False instance GenericDefault () where genericDef = () -- 自定义类型通过Generic自动推导 data User = User String Int deriving (Generic, Show) instance GenericDefault User where genericDef = to ggenericDef -- 自动生成 User "" 0
然后修改parseEOF:
parseEOF :: GenericDefault n => Parser n parseEOF = Parser p where p [] = Just (genericDef, "") p _ = Nothing
关于“()是所有非Void类型子集”的概念
Haskell中并没有直接的“子集”类型概念,但你要表达的核心是所有可居住类型(有至少一个值的类型,即非Void类型)都存在一个默认的“无信息”值。类型类是Haskell表达这种“类型级约束+对应值/操作”的标准方式,通过复用现有类型类(如Default)或结合Generic自动推导,就能避免手动实现大量实例的繁琐。
这种思路也能推广到多值场景:比如需要返回二元组的无信息值时,Default类已经提供了(Default a, Default b) => Default (a,b)的实例,无需额外编写代码就能直接使用。
内容的提问来源于stack exchange,提问作者William Ryman
相关产品推荐
相关产品推荐

