如何编写(Num (Maybe a))实例?及Candle高低差计算的Num实例问题
Alright, let's break down your two Haskell Num instance questions with practical, working code and explanations—no jargon overload, promise!
1. Implementing Num (Maybe a) for arithmetic on wrapped values
To define a Num instance for Maybe a, we first need to ensure the inner type a is itself a Num (since we're doing arithmetic on its values). The core idea is to propagate Nothing through all operations (if any input is missing, the result is missing) and apply standard arithmetic to Just values.
Here's the complete instance:
instance Num a => Num (Maybe a) where -- Addition: Only compute if both values exist Just x + Just y = Just (x + y) _ + _ = Nothing -- Multiplication: Same logic as addition Just x * Just y = Just (x * y) _ * _ = Nothing -- Negation: Flip the sign of a wrapped value; leave Nothing as-is negate (Just x) = Just (negate x) negate Nothing = Nothing -- Absolute value: Apply to wrapped value abs (Just x) = Just (abs x) abs Nothing = Nothing -- Signum: Get the sign of the wrapped value signum (Just x) = Just (signum x) signum Nothing = Nothing -- Convert an integer to Maybe a: Wrap it in Just (since integers are always valid here) fromInteger n = Just (fromInteger n)
This instance behaves exactly as you'd expect:
Just 5 + Just 3returnsJust 8Just 10 * NothingreturnsNothingnegate (Just (-4))returnsJust 4
2. Creating a Num High instance to calculate Candle high-low differences
First, let's assume your core types look like this (adjust if your actual definitions differ):
newtype High = High Double deriving (Show) newtype Low = Low Double deriving (Show) data Candle = Candle { high :: High, low :: Low } deriving (Show)
The error you're seeing happens because:
Highdoesn't have aNuminstance, so you can't use-on itHighandLoware distinct types, so you can't directly subtract aLowfrom aHigh
Step 1: Define the Num High instance
We'll lift the Double Num behavior up to the High newtype—this lets us use arithmetic operators on High values:
instance Num High where High x + High y = High (x + y) High x * High y = High (x * y) negate (High x) = High (negate x) abs (High x) = High (abs x) signum (High x) = High (signum x) fromInteger n = High (fromInteger n)
Step 2: Convert Low to High for subtraction
Since Low and High both wrap numeric values, we can write a simple conversion function to make the types match:
lowToHigh :: Low -> High lowToHigh (Low d) = High d
Step 3: Calculate the high-low difference
Now you can safely compute the difference with type-matched values:
highLowDiff :: Candle -> High highLowDiff candle = high candle - lowToHigh (low candle)
Optional: Add a Num instance for Low (if needed)
If you want to do other arithmetic with Low values, you can mirror the High instance:
instance Num Low where Low x + Low y = Low (x + y) Low x * Low y = Low (x * y) negate (Low x) = Low (negate x) abs (Low x) = Low (abs x) signum (Low x) = Low (signum x) fromInteger n = Low (fromInteger n)
Common pitfalls to avoid
- Forgetting to implement all
Nummethods: Haskell requires every method in the typeclass to be defined (you can't skip(+)just because you only need(-)). - Missing type constraints: Make sure any inner types (like
ainMaybe a) have the necessary constraints (e.g.,Num a).
内容的提问来源于stack exchange,提问作者ktec

