如何借助GHC扩展减少自定义Number类型的样板代码?
减少Haskell样板代码的方案(基于GHC扩展)
可以通过提取通用的类型提升函数,结合GHC的基础扩展(如LambdaCase)消除重复的模式匹配样板,以下是具体实现:
1. 定义通用提升函数
先封装针对Integer和Double的操作到Number类型的逻辑,避免重复编写模式匹配:
{-# LANGUAGE LambdaCase #-} data Operation = Add | Sub | Mult | Div data Number = IntVal Integer | FloatVal Double -- 提升二元操作至Number类型 liftBinOp :: (Integer -> Integer -> Integer) -> (Double -> Double -> Double) -> Number -> Number -> Number liftBinOp intOp floatOp lhs rhs = case (lhs, rhs) of (IntVal i, IntVal j) -> IntVal $ intOp i j (FloatVal x, FloatVal y) -> FloatVal $ floatOp x y _ -> undefined -- 提升一元操作至Number类型(用于Num实例) liftUnOp :: (Integer -> Integer) -> (Double -> Double) -> Number -> Number liftUnOp intOp floatOp = \case IntVal i -> IntVal $ intOp i FloatVal x -> FloatVal $ floatOp x
2. 简化evaluate函数
每个Operation只需绑定对应的运算符,无需重复编写case逻辑:
evaluate :: Operation -> Number -> Number -> Number evaluate Add = liftBinOp (+) (+) evaluate Sub = liftBinOp (-) (-) evaluate Mult = liftBinOp (*) (*) evaluate Div = liftBinOp div (/) -- 整数用div做除法,浮点数用/
3. 简化Num Number实例实现
复用提升函数实现Num的所有方法,避免重复样板:
instance Num Number where (+) = liftBinOp (+) (+) (-) = liftBinOp (-) (-) (*) = liftBinOp (*) (*) negate = liftUnOp negate negate abs = liftUnOp abs abs signum = liftUnOp signum signum fromInteger = IntVal
这种方案把重复的模式匹配逻辑抽离到通用函数中,后续新增操作或扩展类型时,只需补充对应的基础类型操作即可,大幅减少冗余代码。
内容的提问来源于stack exchange,提问作者gust
相关产品推荐
相关产品推荐

