如何在Applicative实例中加入Ord约束?基于ValueRange的金融建模
解决ValueRange在非确定性金融建模中的Applicative约束问题
针对你在非确定性金融建模中使用ValueRange时遇到的标准Applicative无法添加Ord a约束的问题,以下是几种最简单可行的实现方式:
方案1:自定义带Ord约束的专属操作符(最直接)
不用强行适配标准Applicative类型类,直接为ValueRange定义带约束的应用操作符,代码量最少且完全贴合需求:
newtype ValueRange a = ValueRange (a, a) deriving (Show) -- 实现标准Functor实例(fmap不需要Ord约束) instance Functor ValueRange where fmap f (ValueRange (low, high)) = ValueRange (f low, f high) -- 自定义带Ord约束的应用操作符,替代标准<*> (<**>) :: Ord b => ValueRange (a -> b) -> ValueRange a -> ValueRange b ValueRange (fLow, fHigh) <**> ValueRange (xLow, xHigh) = let allResults = [fLow xLow, fLow xHigh, fHigh xLow, fHigh xHigh] newLow = minimum allResults newHigh = maximum allResults in ValueRange (newLow, newHigh)
使用时直接调用<**>即可完成值范围的运算,比如计算EPS边界场景:
-- 示例:计算EPS = (净利润)/(总股本)的范围 netProfitRange :: ValueRange Double netProfitRange = ValueRange (1000000, 2000000) shareCountRange :: ValueRange Double shareCountRange = ValueRange (500000, 1000000) epsRange :: ValueRange Double epsRange = fmap (/) netProfitRange <**> shareCountRange
方案2:用GADT嵌入Ord约束(保留标准Applicative接口)
如果想继续使用标准的<*>操作符,可以用GADT将Ord a约束封装到ValueRange的类型定义中(需要启用GADTs扩展):
{-# LANGUAGE GADTs #-} data ValueRange a where ValueRange :: Ord a => (a, a) -> ValueRange a instance Functor ValueRange where fmap f (ValueRange (low, high)) = ValueRange (f low, f high) instance Applicative ValueRange where pure x = ValueRange (x, x) ValueRange (fLow, fHigh) <*> ValueRange (xLow, xHigh) = let allResults = [fLow xLow, fLow xHigh, fHigh xLow, fHigh xHigh] in ValueRange (minimum allResults, maximum allResults)
这种方式可以直接使用标准Applicative的所有语法,比如liftA2等组合子,无需额外自定义操作符。
方案3:自定义带约束的类型类(适合多类型扩展)
如果后续需要为其他类型也实现带Ord约束的应用逻辑,可以自定义专属类型类:
class OrdApplicative f where opure :: a -> f a oapply :: Ord b => f (a -> b) -> f a -> f b instance OrdApplicative ValueRange where opure x = ValueRange (x, x) oapply (ValueRange (fLow, fHigh)) (ValueRange (xLow, xHigh)) = let allResults = [fLow xLow, fLow xHigh, fHigh xLow, fHigh xHigh] in ValueRange (minimum allResults, maximum allResults)
该方案扩展性更强,但相比前两种实现成本略高。
内容的提问来源于stack exchange,提问作者Dominik G
相关产品推荐
相关产品推荐

