67 lines
1.8 KiB
Haskell
67 lines
1.8 KiB
Haskell
-- error handling with a custom monad
|
|
-- say we want to divide a list of numbers by a divisor
|
|
-- if the divisor is even, we throw an error, then apply ^2 to the rest of the numbers
|
|
-- if the divisor is odd, we return the result
|
|
-- if the divisor is 0, we throw an error
|
|
|
|
-- custom monad
|
|
data MyMonad a = DivByZeroError String | DivByEven a | DivByOdd a deriving (Show)
|
|
|
|
-- instance of Functor
|
|
instance Functor MyMonad where -- Functor is where we define fmap (i.e. map)
|
|
-- customMap, where we have 2 functions, one for even and one for odd
|
|
fmap f (DivByZeroError s) = DivByZeroError s
|
|
fmap f (DivByEven a) = DivByEven (f a)
|
|
fmap f (DivByOdd a) = DivByOdd (f a)
|
|
|
|
-- instance of Applicative
|
|
instance Applicative MyMonad where
|
|
(DivByZeroError s) <*> _ = DivByZeroError s
|
|
-- DivByEvenError -> ^2
|
|
(DivByEven a) <*> b = fmap a b --
|
|
(DivByOdd a) <*> b = fmap a b
|
|
pure = DivByOdd
|
|
|
|
-- instance of Monad
|
|
instance Monad MyMonad where
|
|
return = pure
|
|
(DivByZeroError s) >>= _ = DivByZeroError s
|
|
(DivByEven a) >>= f =
|
|
case f a of
|
|
DivByOdd b -> DivByEven b -- propagate the "evenness context" forward
|
|
DivByEven b -> DivByEven b -- keep even state if it continues
|
|
DivByZeroError s -> DivByZeroError s
|
|
(DivByOdd a) >>= f = f a
|
|
|
|
safeDivide :: Int -> [Int] -> MyMonad [Int]
|
|
safeDivide 0 _ = DivByZeroError "Division by zero"
|
|
safeDivide d xs
|
|
| even d = DivByEven (map (^2) xs)
|
|
| otherwise = DivByOdd (map (`div` d) xs)
|
|
|
|
main :: IO ()
|
|
main = do
|
|
let nums = [69, 420, 666, 1337]
|
|
let divisor = 2
|
|
let result = safeDivide divisor nums
|
|
|
|
let nums2 = [1,2,3,4,5]
|
|
let divisor2 = 0
|
|
let result2 = safeDivide divisor2 nums2
|
|
|
|
let nums3 = [69, 420, 666, 1337]
|
|
let divisor3 = 3
|
|
let result3 = safeDivide divisor3 nums3
|
|
|
|
print result
|
|
print result2
|
|
print result3
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|