Reputation:
I wrote a typeclass to avoid having to write a duplicate function for a different type as below:
import Statistics.Distribution.Normal
import Data.Random
d1 :: Double -> Double -> Double -> Double -> Double -> Double
d1 s k r v t = ( log ( s / k ) + ( ( v * v ) / 2 ) * t ) / ( v * sqrt t )
d2 :: Double -> Double -> Double -> Double -> Double -> Double
d2 s k r v t = d1 s k r v t - v * sqrt t
call :: Double -> Double -> Double -> Double -> Double -> Double
call s k r t v = exp ( -r * t ) * ( s * cdf normal ( d1 s k r v t )
- k * cdf normal ( d2 s k r v t ) )
where normal = Normal (0 :: Double) 1
put :: Double -> Double -> Double -> Double -> Double -> Double
put s k r t v = exp ( -r * t ) * ( k * cdf normal ( - d2 s k r v t )
- s * cdf normal ( - d1 s k r v t ) )
where normal = Normal (0 :: Double) 1
class Black a where
price :: a -> Double -> Double -> Double
instance Black ( Option Future ) where
price ( Option ( Future s ) Call European k t ) r v = call s k r t v
price ( Option ( Future s ) Put European k t ) r v = put s k r t v
instance Black ( Option Forward ) where
price ( Option ( Forward s ) Call European k t ) r v = call s k r t v
price ( Option ( Forward s ) Put European k t ) r v = put s k r t v
Is this a valid use of typeclasses? The reason I am asking is that I am not overloading the definition of the price function for any given type. All I am doing is avoiding having to write:
priceFuture :: (Option Future) -> Double -> Double -> Double
// impl
priceFoward :: (Option Forward) -> Double -> Double -> Double
impl
data Option a = Option a Type Style Strike Expiration deriving (Show)
data Future = Future Price deriving (Show)
data Forward = Forward Price deriving (Show)
type Barrier = Double
type Expiration = Double
type Price = Double
type Strike = Double
type Value = Double
type Dividend = Double
type Rate = Double
data Type = Call | Put deriving (Eq, Show)
data Style = European | American deriving (Eq, Show)
Upvotes: 1
Views: 119
Reputation: 153342
I think I would just make the the argument to Option
be a phantom type:
data Option a = Option Price Type Style Strike
data Future
data Forward
price :: Option a -> Double -> Double -> Double
price (Option s Call European k t) r v = call s k r t v
price (Option s Put European k t) r v = put s k r t v
Much less repetition, and no need for a type-class, but you still get a type-level distinction between forward options (Option Forward
) and future options (Option Future
) should you need that elsewhere. If you're really excited, you could turn on DataKinds
to make sure that Future
and Forward
are the only two possible type-level arguments to Option
.
Upvotes: 5
Reputation: 7755
How about this?
data Option = Option ForFut Type Style Strike Expiration deriving (Show)
data ForFut = Forward Price | Future Price deriving (Show)
type Barrier = Double
type Expiration = Double
type Price = Double
type Strike = Double
type Value = Double
type Dividend = Double
type Rate = Double
data Type = Call | Put deriving (Eq, Show)
data Style = European | American deriving (Eq, Show)
call :: Double -> Double -> Double -> Double -> Double -> Double
call = undefined
put :: Double -> Double -> Double -> Double -> Double -> Double
put = undefined
price :: Option -> Double -> Double -> Double
price ( Option ( Future s ) Call European k t ) r v = call s k r t v
price ( Option ( Future s ) Put European k t ) r v = put s k r t v
price ( Option ( Forward s ) Call European k t ) r v = call s k r t v
price ( Option ( Forward s ) Put European k t ) r v = put s k r t v
So I've combined the Forward
and Future
types into a single type. This then avoids the need to make Option
a higher kinded type. The type class can then be removed, and price
can be defined with simple pattern matching.
Upvotes: 1